Form Automation
Form filling is the highest-value thing an in-app agent does — and the place where sloppy metadata hurts most. This guide covers how to make a form the agent can fill correctly on the first try.
1. Register every field
Each input the agent should fill needs a registry entry. Pick the mechanism that fits your codebase (details in Registering elements):
-
Hooks, for precise control:
const [plate, setPlate] = useState('');useAppilotsField('plate', {value: plate,onChangeText: setPlate,fieldType: 'text',label: 'License Plate',screen: 'VehicleCreate',});Use
useAppilotsTogglefor switches anduseAppilotsSlider(withmin,max,step) for numeric ranges — the executor clamps and snaps slider values for you. -
Auto-tracking, for existing forms: enable
enableAppilotsAutoTracking()and give eachTextInputatestID. ThetestIDbecomes the field id. -
HOC factories (
createAppilotsInput), if you have a design-system input component — wrap it once and every instance registers itself from itslabelprop.
2. Describe the form in registerScreen
Registration makes fields operable; screen metadata makes them understandable. Declare labels, types, required flags, and options:
registerScreen({
name: 'VehicleCreate',
title: 'New Vehicle',
description: 'Form to register a new vehicle for the account.',
fields: [
{ id: 'plate', label: 'License Plate', type: 'text', required: true },
{ id: 'model', label: 'Model', type: 'text', required: true },
{
id: 'fuelType',
label: 'Fuel Type',
type: 'select',
required: false,
options: [
{ label: 'Gasoline', value: 'gasoline' },
{ label: 'Electric', value: 'electric' },
],
},
],
actions: [
{
id: 'submitVehicle',
label: 'Save Vehicle',
type: 'submit',
effect: 'write',
riskLevel: 'low',
},
],
});
The CLI also extracts much of this from your JSX
statically, but explicit registerScreen metadata is authoritative and
survives refactors better. The generated
MCP document carries it all to the agent.
3. Fill-and-submit in one step
A form_fill action can carry submitAfterFill: true
(see Agent actions), meaning: after all fields
are set, press the screen's primary submit button. The submit button is
resolved from your registerScreen metadata first — declare an action with
type: 'submit' (as above) so resolution is exact rather than heuristic.
If submission is a mutating or risky operation, say so — effect: 'write'
at minimum, riskLevel: 'high'/requiresConfirmation: true for anything
the user should approve explicitly. The
metadata lint flags submit actions missing this.
Practical tips
- Ids and labels are the interface. The agent matches user intent
("fill in the plate") against your field ids and labels.
platewith label "License Plate" works;input3doesn't. - Prefer explicit
fieldType.select,date,number, andtogglefields behave differently at fill time — don't make the executor guess. - Mark required fields. The agent uses
requiredto know when a form is complete enough to submit. - Keep option values enumerable. For
selectfields, provideoptionsso the agent maps "electric car" toelectricinstead of free-typing. - Test with identifiable values. Ask the agent to "create a vehicle with plate TEST-0001" and confirm exactly that value lands in exactly that field.
Troubleshooting
If the agent fills the wrong field or reports it can't find one, check the
resolution chain in Troubleshooting — it's almost
always a missing/ambiguous field id or a stale MCP document
(appilots sync fixes the latter).
Related
- Registering elements
- Multi-screen workflows — forms reached through navigation
- Custom actions — what happens after submit