---
name: field-service-data-capture-reference-configure
description: "Build, edit, and deploy Salesforce Data Capture Flows (processType DataCaptureFlow) — Field Service mobile / offline forms. Use when authoring flow-meta.xml with runtime_service_fieldservice:dc* components, Repeater loops (.AllItems), master-detail child record persistence, visual polish (gradient banners, progress bars, callouts), supporting objects with FLS/permsets, debugging DataCaptureFlow deploy errors, or troubleshooting why a deployed form doesn't appear on the FSL Mobile Forms tab (DDC/WorkPlan OWD + AssignedResource sharing prerequisites)."
user-invocable: false
metadata:
  version: "1.0"
  domains: ["Field Service"]
  cliTools:
    - tool: ["python3"]
      semver: ">=3.9.0"
    - tool: ["sf"]
      semver: ">=2.0.0"
---

# Querying Fs Data Capture Reference

## When to Use This Skill

Build, edit, and deploy Salesforce Data Capture Flows (processType DataCaptureFlow) — Field Service mobile / offline forms. Use when authoring flow-meta.xml with runtime_service_fieldservice:dc* components, Repeater loops (.AllItems), master-detail child record persistence, visual polish (gradient banners, progress bars, callouts), supporting objects with FLS/permsets, debugging DataCaptureFlow deploy errors, or troubleshooting why a deployed form doesn't appear on the FSL Mobile Forms tab (DDC/WorkPlan OWD + AssignedResource sharing prerequisites).

## Workflow

# Salesforce Data Capture Flow Skill

Build, edit, and deploy Salesforce Flows with `processType: DataCaptureFlow` (Field Service mobile / offline forms).

---

## Required metadata (every flow)

```xml
<processType>DataCaptureFlow</processType>
<areMetricsLoggedToDataCloud>false</areMetricsLoggedToDataCloud>
<environments>Offline</environments>
<!-- NO <apiVersion> tag -->
```

Optional `IsLlmTargetable` custom property — if you include it, it must be a JSON string, not a boolean:

```xml
<customProperties>
    <name>IsLlmTargetable</name>
    <value><stringValue>{&quot;value&quot;:&quot;false&quot;}</stringValue></value>
</customProperties>
```

The `<booleanValue>false</booleanValue>` form deploys but blocks activation — error: `The value of the IsLlmTargetable custom property's value field must be a string in JSON format`. Omitting the property entirely is also fine.

---

## XML structure rules

Salesforce's Flow schema enforces grouping — all elements of the same type must appear in a single contiguous block. Deploy fails with `Element X is duplicated at this location` when violated.

Group order doesn't matter, but within each group elements must be adjacent:
- all `<choices>` together
- all `<dynamicChoiceSets>` together
- all `<screens>` together
- all `<decisions>` together
- all `<recordLookups>` together
- all `<recordCreates>` together
- all `<recordUpdates>` together
- all `<loops>` together
- all `<assignments>` together
- all `<variables>` together

Connector references determine execution order, not XML order.

---

## Component reference

All extensions: prefix `runtime_service_fieldservice:`

| Component | Extension | fieldType |
|-----------|-----------|-----------|
| Short Text | `dcTextInput` | `ComponentInstance` |
| Long Text | `dcLongText` | `ComponentInstance` |
| Email | `dcEmail` | `ComponentInstance` |
| Phone | `dcPhone` | `ComponentInstance` |
| Name | `dcName` | `ComponentInstance` |
| Numeric | `dcNumeric` | `ComponentInstance` |
| Counter | `dcCounter` | `ComponentInstance` |
| Date | `dcDate` | `ComponentInstance` |
| Date & Time | `dcDateTime` | `ComponentInstance` |
| Checkbox | `dcCheckbox` | `ComponentInstance` |
| Toggle | `dcToggle` | `ComponentInstance` |
| Address / GPS | `dcAddress` | `ComponentInstance` |
| Lookup | `dcLookup` | `ComponentInstance` |
| Static image | `dcFileView` | `ComponentInstance` |
| Upload image (mobile) | `dcUpImage` | `ComponentInstance` |
| Upload file (mobile) | `dcUpFile` | `ComponentInstance` |
| Signature (mobile) | `dcSignature` | `ComponentInstance` |
| Picklist single | `dcPicklist` | `ComponentChoice` |
| Picklist multi | `dcPicklist` | `ComponentMultiChoice` |
| Radio buttons | `dcRbGroup` | `ComponentChoice` |
| Checkbox group | `dcCbGroup` | `ComponentMultiChoice` |
| Matrix | `dcMatrix` | `ComponentMultiChoice` |
| Display text | *(none)* | `DisplayText` |
| Section | *(none)* | `RegionContainer` + `Region` |
| Repeater | *(none)* | `Repeater` |

Note: `<fieldType>Range</fieldType>` is NOT a valid slider fieldType in DataCaptureFlow (despite "Range/Slider" appearing in Builder UI lists). Sliders aren't available as pure metadata in this process type — use `dcNumeric` or `dcCounter`. `forceContent:repeater` (Lightning generic) ≠ `<fieldType>Repeater</fieldType>` (FSL offline). They share a concept, not XML.

### Setting the label

| fieldType | How |
|-----------|-----|
| `ComponentInstance` | `<inputParameters><name>label</name><value><stringValue>…</stringValue></value></inputParameters>` |
| `ComponentChoice` / `ComponentMultiChoice` | `<fieldText>Label</fieldText>` |
| `DisplayText` | `<fieldText>HTML</fieldText>` |

All ComponentInstance extensions (including `dcAddress` and `dcToggle`) accept the `label` inputParameter — no wrapping DisplayText needed.

### Required flag

Every input field needs `<isRequired>true/false</isRequired>` at field level. That single flag is sufficient for every `dc*` component — no extra `required` / `isRequired` inputParameter is needed.

`dcLookup` additionally accepts an `isRequired` inputParameter (boolean), but the field-level `<isRequired>` drives enforcement.

`dcCheckbox` and `dcToggle` accept `<isRequired>true</isRequired>` syntactically but don't enforce it at runtime.

### Every input field must also have

```xml
<inputsOnNextNavToAssocScrn>UseStoredValues</inputsOnNextNavToAssocScrn>
<storeOutputAutomatically>true</storeOutputAutomatically>
<styleProperties>
    <verticalAlignment><stringValue>top</stringValue></verticalAlignment>
    <width><stringValue>12</stringValue></width>
</styleProperties>
```

**Exception:** `<fieldType>Repeater</fieldType>` explicitly rejects `storeOutputAutomatically` (`"the storeOutputAutomatically field isn't supported"`). Repeater output is always available as `.AllItems` — no opt-in needed.

---

## Screen rules

Every screen needs ALL THREE of these or the Next/Finish button won't render:
- `<allowFinish>true</allowFinish>` (even on non-final screens)
- `<showFooter>true</showFooter>`
- `<nextOrFinishButtonLabel>Next</nextOrFinishButtonLabel>`

Plus:
- First element after `<start>` must always be a `<screens>` element
- All `<screens>` elements must be grouped together in the XML

---

## Repeater — iterating rows and creating child records

The Repeater's output collection is exposed as `.AllItems`. Confirmed working on API v66.

```xml
<!-- On the screen: -->
<fields>
    <name>MyRepeater</name>
    <fieldType>Repeater</fieldType>
    <!-- NO storeOutputAutomatically on the Repeater itself -->
    <fields>
        <name>Row_PartName</name>
        <extensionName>runtime_service_fieldservice:dcTextInput</extensionName>
        <fieldType>ComponentInstance</fieldType>
        <storeOutputAutomatically>true</storeOutputAutomatically>
        <!-- … -->
    </fields>
    <fields>
        <name>Row_PartQty</name>
        <extensionName>runtime_service_fieldservice:dcCounter</extensionName>
        <fieldType>ComponentInstance</fieldType>
        <storeOutputAutomatically>true</storeOutputAutomatically>
        <!-- … -->
    </fields>
    <isRequired>false</isRequired>
</fields>

<!-- At end of flow: -->
<loops>
    <name>Loop_Parts</name>
    <collectionReference>MyRepeater.AllItems</collectionReference>   <!-- ← THE KEY -->
    <iterationOrder>Asc</iterationOrder>
    <nextValueConnector>
        <targetReference>Create_Part</targetReference>
    </nextValueConnector>
</loops>
<recordCreates>
    <name>Create_Part</name>
    <object>CustomFormPart__c</object>
    <connector>
        <targetReference>Loop_Parts</targetReference>   <!-- loops back -->
    </connector>
    <inputAssignments>
        <field>PartName__c</field>
        <value>
            <elementReference>Loop_Parts.Row_PartName.value</elementReference>
            <!-- ↑ LOOP name + nested field name + .value -->
        </value>
    </inputAssignments>
    <inputAssignments>
        <field>Quantity__c</field>
        <value>
            <elementReference>Loop_Parts.Row_PartQty.value</elementReference>
        </value>
    </inputAssignments>
    <storeOutputAutomatically>true</storeOutputAutomatically>
</recordCreates>
```

**Don'ts:**
- `<collectionReference>MyRepeater</collectionReference>` → `Element "MyRepeater" doesn't exist`
- `<collectionReference>MyRepeater.items</collectionReference>` → generic server error
- `<collectionReference>MyRepeater.data</collectionReference>` → generic server error
- Inside the loop body, `MyRepeater.Row_PartName.value` won't work — must use the **loop's name**, not the repeater's name.

**Cross-row validation does NOT compile.** Formula refs like `r_GR4.AllItems[$Items].field.value` and `r_GR4.AllItems[$Items - 1].field.value` fail with *Syntax error*. Per-row validation works via plain `fieldName.value` inside the nested field's own `validationRule`. For cross-row rules, use a post-screen `loops + decisions`.

**Other Repeater accessors don't resolve today.** Only `.AllItems` works. `AddedItems`, `PrepopulatedItems`, `RemovedItems` all fail deploy with `doesn't exist`.

### Prepopulating a Repeater from an existing collection

Bind an existing SObject collection to the Repeater so it renders one pre-filled row per source record. The user can then edit, add, or remove rows before submit.

Pattern: `recordLookups` (get source collection, `getFirstRecordOnly=false`, `storeOutputAutomatically=true`) → screen with `Repeater` bound via the `collection` inputParameter → nested fields use `SourceCollection[$EachItem].FieldApiName` as their `value` default.

```xml
<recordLookups>
    <name>Get_Source</name>
    <object>ServiceResource</object>
    <getFirstRecordOnly>false</getFirstRecordOnly>
    <storeOutputAutomatically>true</storeOutputAutomatically>
    <connector><targetReference>Screen_Repeater</targetReference></connector>
    <!-- optional <limit>, <filters> … -->
</recordLookups>

<!-- On the screen: -->
<fields>
    <name>accountRepeater</name>
    <fieldType>Repeater</fieldType>
    <inputParameters>
        <name>collection</name>                                <!-- ← binds source rows -->
        <value><elementReference>Get_Source</elementReference></value>
    </inputParameters>
    <fields>
        <name>account_info</name>
        <fieldType>DisplayText</fieldType>
        <fieldText>&lt;p&gt;Id: {!Get_Source[$EachItem].Id}&lt;/p&gt;</fieldText>
        <!-- DisplayText inside the Repeater merges via SourceCollection[$EachItem].Field -->
    </fields>
    <fields>
        <name>name</name>
        <extensionName>runtime_service_fieldservice:dcTextInput</extensionName>
        <fieldType>ComponentInstance</fieldType>
        <inputParameters>
            <name>label</name>
            <value><stringValue>Name</stringValue></value>
        </inputParameters>
        <inputParameters>
            <name>value</name>
            <value><elementReference>Get_Source[$EachItem].Name</elementReference></value>
            <!-- ↑ prepopulates the editable field with the source record's value -->
        </inputParameters>
        <isRequired>true</isRequired>
        <storeOutputAutomatically>true</storeOutputAutomatically>
        <inputsOnNextNavToAssocScrn>UseStoredValues</inputsOnNextNavToAssocScrn>
        <styleProperties>…</styleProperties>
    </fields>
    <isRequired>false</isRequired>
    <styleProperties>…</styleProperties>
</fields>
```

Key points:
- The binding inputParameter is named `collection`, not `value` or `source`.
- Inside the Repeater, reference a source row via `SourceCollectionName[$EachItem].FieldApiName` — use the **record-lookup's name**, not the Repeater's name. Works in both `DisplayText.fieldText` (as `{!Get_Source[$EachItem].Id}`) and in component `value` defaults (as `<elementReference>Get_Source[$EachItem].Name</elementReference>`).
- `$EachItem` is the per-row iterator Salesforce injects while rendering the Repeater. It only resolves inside Repeater-nested fields.
- Downstream loops still iterate `Repeater_Name.AllItems` as normal — prepopulation changes the input, not the output accessor.
- Prepopulated rows appear as regular `.AllItems` entries after submit; there is no `PrepopulatedItems` / `AddedItems` split (those accessors fail deploy).

### Displaying Repeater entries to the user (post-Repeater Loop screen)

To show the user what they captured (e.g. review / confirmation / per-row detail), put a Loop **after** the Repeater screen whose body connects to a display screen; the display screen then connects back to the Loop. The end connector of the Loop moves on to the next step.

```xml
<loops>
    <name>Loop_Through_Repeater</name>
    <collectionReference>accountRepeater.AllItems</collectionReference>
    <iterationOrder>Asc</iterationOrder>
    <nextValueConnector>
        <targetReference>Repeater_Output_Screen</targetReference>   <!-- body = display screen -->
    </nextValueConnector>
    <!-- <noMoreValuesConnector> → next step after the review is done -->
</loops>

<screens>
    <name>Repeater_Output_Screen</name>
    <connector><targetReference>Loop_Through_Repeater</targetReference></connector>   <!-- back to loop -->
    <fields>
        <name>display_info</name>
        <fieldType>DisplayText</fieldType>
        <fieldText>&lt;p&gt;Source Id: {!Loop_Through_Repeater.UniqueField__Id}&lt;/p&gt;
&lt;p&gt;Name: {!Loop_Through_Repeater.name.value}&lt;/p&gt;
&lt;p&gt;Type: {!Loop_Through_Repeater.description.value}&lt;/p&gt;</fieldText>
        <styleProperties>…</styleProperties>
    </fields>
    <allowFinish>true</allowFinish>
    <showFooter>true</showFooter>
    <nextOrFinishButtonLabel>Next</nextOrFinishButtonLabel>
</screens>
```

Accessor rules inside the loop body:
- User-captured values — `{!LoopName.nestedFieldName.value}` (same `.value` / `.selectedChoiceValues` / `.isActive` / etc. accessors as elsewhere).
- Source record Id for **prepopulated** rows — `{!LoopName.UniqueField__Id}`. This is a synthetic field the Repeater exposes on each iteration; it only carries a value for rows that came from the bound `collection` (new rows the user added will be blank).
- Use the **loop's name**, not the Repeater's name, inside the loop body — same rule as the canonical `.AllItems` + Create pattern above.

This loop-over-`.AllItems` display pattern composes with the Create/Update patterns: one loop for rendering a review screen, a later loop (or the same one, if ordering permits) for CUD. Remember the CUD rule — nothing (screens, gets, decisions) may sit between sequential CUD nodes, so any review loop must fully complete before the CUD chain starts.

---

## CUD rules (hard platform constraints)

- **A Decision can choose which CUD chain starts** (e.g. Create vs Update branches of a save-mode decision). But **once a CUD chain begins, no Decision may appear between sequential CUD nodes** — deploy fails with `Append multiple Create, Update, or Delete operations only at the end of the flow, in any order`.
  - Workaround for "create only if filled" → always-create (accept blank rows), or move the conditional logic before the CUD chain begins.
- **All CUDs at end of flow.** No Get Records or screens after any CUD. No subflows containing CUD.
- **Assignment-after-CUD inside a loop was bugged in v260.** Fixed in v262 / API 66. Safe to use now.

---

## Counter params

```xml
<inputParameters><name>min</name><value><numberValue>1.0</numberValue></value></inputParameters>
<inputParameters><name>max</name><value><numberValue>10.0</numberValue></value></inputParameters>
<inputParameters><name>step</name><value><numberValue>1.0</numberValue></value></inputParameters>
<inputParameters><name>minCustomErrorMessage</name><value><stringValue>…</stringValue></value></inputParameters>
<inputParameters><name>maxCustomErrorMessage</name><value><stringValue>…</stringValue></value></inputParameters>
```

## Date params

```xml
<inputParameters><name>minDate</name><value><elementReference>$Flow.CurrentDate</elementReference></value></inputParameters>
<inputParameters><name>maxDate</name><value><dateValue>2027-12-31</dateValue></value></inputParameters>
```

## Picklist compact mode

Only use `isCompact=true` when ALL labels ≤8 characters AND ≤5 options.

## Lookup params

```xml
<inputParameters><name>objectApiName</name><value><stringValue>Asset</stringValue></value></inputParameters>
<inputParameters><name>searchedFields</name><value><stringValue>Name, SerialNumber</stringValue></value></inputParameters>
<inputParameters><name>isMultiSelection</name><value><booleanValue>true</booleanValue></value></inputParameters>
<inputParameters><name>recordIdCollection</name><value><elementReference>v_Ids</elementReference></value></inputParameters>
```

### `recordIdCollection` — scoping the searchable set

- **Builder label:** *Record IDs Collection*. **XML attribute:** `recordIdCollection` (singular `recordId` + `Collection` suffix). `recordIds` fails deploy with `We can't find this input attribute: "recordIds"`.
- **It is a scoping filter, not a default pre-selection.** Constrains the lookup to only search within the provided String collection of Ids.
- **Only takes effect when `isMultiSelection=true`.** In single-select mode it is silently ignored — the user sees the full unfiltered object.
- Canonical pattern: `recordLookups` (scoped subset) → `loops` + `assignments` (build String collection of Ids) → screen with `dcLookup recordIdCollection=v_Ids`. Works offline against Briefcase-primed data; target < 1s over ~60k records.
- Output in multi-select mode is `{!Lookup.recordIds}` (String collection); visibility rules and DML that previously used `{!Lookup.recordId}` (singular) must iterate the collection or take the first element.

### `dcLookup` displayed label

`dcLookup` has **no input parameter** for the displayed field (no `displayField`/`primaryField`). The label in search results and the selected chip is driven by the object's **Primary Compact Layout** — first field in that layout wins. To change it: Setup → Object Manager → *Object* → Compact Layouts → reorder → assign as Primary (org-wide change). `searchedFields` controls matching, not display.

Flow-local alternative: swap `dcLookup` for `dcPicklist` backed by a `dynamicChoiceSets` with `<displayField>` / `<valueField>`.

## Address with GPS

```xml
<inputParameters><name>useCoordinates</name><value><booleanValue>true</booleanValue></value></inputParameters>
```

## Matrix

```xml
<inputParameters><name>questions</name><value><stringValue>["Q1","Q2","Q3"]</stringValue></value></inputParameters>
```

Escape `&` as `&amp;` inside the JSON string.

## 2-column section

```xml
<fields>
    <name>MySection</name>
    <fieldText>Section Header</fieldText>
    <fieldType>RegionContainer</fieldType>
    <fields>
        <name>MySection_Col1</name>
        <fieldType>Region</fieldType>
        <fields><!-- components here --></fields>
        <inputParameters><name>width</name><value><stringValue>6</stringValue></value></inputParameters>
        <isRequired>false</isRequired>
    </fields>
    <fields>
        <name>MySection_Col2</name>
        <fieldType>Region</fieldType>
        <fields><!-- components here --></fields>
        <inputParameters><name>width</name><value><stringValue>6</stringValue></value></inputParameters>
        <isRequired>false</isRequired>
    </fields>
    <isRequired>false</isRequired>
    <regionContainerType>SectionWithHeader</regionContainerType>
    …styleProperties…
</fields>
```

## Visibility rule

```xml
<visibilityRule>
    <co