Help & documentation
The complete guide to Flowroid, the Android automation platform where your phone is the server. Build flows that react to what your device sees and does, control hardware and apps, and expose it all to external systems through an embedded HTTP API. Automation runs locally — no account, no cloud relay — and the optional AI assistant builds and runs it for you when you ask.
- Platform
- Android 8.0 (API 26) and newer
- Designed for
- Android 14 (target API 35)
- Works on
- Phones, tablets, Chromebooks
- Privacy
- Automation runs entirely on-device
On this page
Core concepts
Flowroid automations are called flows. A flow is three parts that run in sequence. That is what a flow is; how you assemble one is two builders, and both produce this same shape.
Starts on
Triggers
A device event starts the flow — a notification arrives, you reach a location, the battery drops. A flow can have one or more.
Guarded by
Conditions
Optional checks evaluated when a trigger fires. The flow only continues if they pass. An empty group passes.
Then runs
Actions
What the flow does, in order. Each action can read the output of the ones before it. Every run is logged to history.
Flows are event-driven — they react to events rather than polling — and fail gracefully: if one action errors, the flow logs it and either continues, retries, or stops based on your settings, but never crashes the app.
On the canvas each of those parts is a node, and the order is the wire you draw between them. Conditions appear either as a guard on the whole flow or as a branch mid-run; loops and sub-flows are nodes too. The vocabulary is the same everywhere in the app — the trigger → conditions → actions line you see when the assistant proposes a flow is describing exactly this.
Getting started
Install & first launch
- Install Flowroid from Google Play and open it.
- On first launch you're guided through the Permissions overview, where you grant only the permissions the features you want require.
- Flowroid starts a persistent foreground service that keeps your automations alive. The small ongoing notification shows how many flows are active — that's what lets flows run when the app isn't open.
Create your first flow
There are three places to start, and the + button on the Flows screen holds two of them:
- Templates — 63 ready-made automations. Pick one, adjust its times, places, apps and thresholds, install it. This is the fastest first flow, and what you install is an ordinary flow you can open and change. See Templates.
- + → Blank canvas — the visual builder. An empty canvas that asks for a trigger first, then whatever should follow it.
- + → Create with AI — describe the automation in a sentence and it drafts the flow for you to review. See Build with AI.
A flow you build yourself is saved switched on and runs the next time its trigger fires. A flow the AI drafts is saved switched off until you have read it and turned on Run automatically. Either way, the permissions the flow needs are named before it can do anything, and every run is recorded in the flow's execution history.
Building flows
Flowroid has exactly two builders. You draw the flow on a canvas, or you describe it and read back what the assistant drafted. There is no third path and no wizard — installing a template drops you into the same canvas with the nodes already placed.
The visual builder
Flows → + → Blank canvas
A node canvas. You drop a trigger, drop the actions after it, and wire them together in the order they should run.
- A searchable palette of every trigger and action on the device, in four sections — Triggers, Actions, Logic (branch and loop), Utility (delay, variable, log, comment).
- Drag a wire out of a node and drop it on empty canvas: the palette reopens filtered to the node types that can legally connect there.
- Tap a node to configure it. The form is generated from that trigger or action’s own schema, so you only see fields it actually has.
- Pan, zoom, fit-to-view, a minimap, snap-to-grid, auto-arrange with direction and spacing, undo and redo by name, and copy / cut / paste.
- Save is blocked while the flow is invalid, and the message names the node and the field — tap Fix to jump straight to it.
- Run it once from the toolbar without waiting for its trigger, and read the result in execution history.
On saveSaved switched on. It runs the next time its trigger fires.
Build with AI
Flows → + → Create with AI
Describe the automation in a sentence and the assistant drafts it, then shows you the flow it means to build before anything is saved.
- It asks a clarifying question when the request is genuinely ambiguous rather than guessing at the answer.
- The draft is shown as the flow it will become — the trigger, the conditions, and the actions in order — with a plain-language explanation of what it does.
- It names the honest problems up front: an action this build does not have, a flow with no trigger, a reference no earlier step can satisfy, and any permission the flow needs and does not have — with a button to grant it.
- Refine it in words (“only on weekdays”, “notify me instead”) and it redrafts. Ask to change a flow you already saved and it shows the new version against the live one, which is untouched until you apply it.
- Open it in the visual builder at any point. It is an ordinary flow from there on — nothing about it is locked or AI-only.
- The assistant can draft a flow mid-conversation too, returning the same review as a card in the transcript — so you can read and keep a flow without leaving the chat.
On saveSaved switched off, so you can read it before it can run. One tap on Run automatically turns it on.
Both produce the same thing — one flow, made of the same triggers, conditions and actions, stored in the same place and run by the same on-device engine. A flow you drafted by asking is fully editable on the canvas, and a flow you drew by hand can be revised by asking. Nothing you build depends on AI to keep running.
Working on the canvas
Both builders end here, so it is worth knowing the surface. Nodes carry ports: a trigger has an output and no input, because it is where the flow starts; an action has one of each; a condition has a true port and a false port; a loop has a body port and a done port. Dragging a wire from a port onto empty canvas reopens the palette filtered to the node types that can legally connect to it, so a connection you can draw is a connection that will run.
Tapping a node opens its configuration form, generated from that trigger or action's own schema — you only ever see fields it actually has, and the form documents the {{previous.*}} outputs the node makes available to whatever comes after it. Saving is blocked while the flow is invalid, and the message names the node and the field rather than the fact; Fix jumps to it.
The toolbar carries the rest: undo and redo (labelled with the step they will reverse), fit-to-view, auto-arrange with a direction and spacing, a dot-or-line grid with snapping, copy / cut / paste, a minimap, and a test run that executes the flow once without waiting for its trigger. Leaving with unsaved changes asks first.
Build with AI, in detail
Create with AI is one-shot: you describe the automation, it asks a clarifying question if the request is genuinely ambiguous, and it comes back with the flow it means to build — the trigger, the conditions and the actions in order, plus a plain-language explanation. From there you can refine it in words, regenerate it, create it, or open it in the canvas and finish by hand.
The assistant can also draft a flow in the middle of a conversation. It returns the same review — the same pipeline, the same explanation — as a card in the transcript, so you can read and keep a flow without leaving the chat. Asking it to change a flow you already saved is handled as an update: it shows the new version, tells you the live flow has not changed, and applying it replaces the definition while keeping the flow's enabled state, its pin, and its run history.
What the draft tells you honestly
A drafted flow is checked before you are offered it, and the problems are named on the card rather than discovered later: an action this build does not have, a flow with no trigger, a {{previous.*}} reference no earlier step can satisfy, and every permission the flow needs and does not have — listed by name, with a button that opens the grant flow. Nothing is saved until you say so, and what is saved is switched off.
Action chaining & outputs
Actions run sequentially. Every action produces structured outputs that later actions can reference using template expressions. For example, an HTTP Request action exposes statusCode, headers, body, and latency, which a following action reads with {{previous.http.body}}.
Control flow
First-class control-flow actions let a flow branch, loop, and call sub-flows:
- If / Else — run one set of nested actions or another based on a condition group.
- Loop — repeat nested actions
forEachitem, a fixed number oftimes, orwhilea condition holds (with amaxIterationssafety cap). - Call Sub-Flow — invoke another flow and pass it an input object, enabling reusable building blocks.
- Delay, Stop, Log, plus Math, String, and Array helpers for in-flow data manipulation.
Error handling
Each action can be configured to continue, stop, or retry on error. Failures are recorded in the flow's execution history with logs, so you can see exactly what happened and when.
Trigger catalog
Flowroid ships 32 triggers. Permissions noted are only required if you use that trigger. Two of them are not device events at all: Webhook Received is something on your network calling the phone (§12), and Manual is you, from a Quick Settings tile, a launcher shortcut, a home-screen widget, a notification button, or the API.
Notifications
1- Notification Received
notification.postedA notification is posted.
Filter by package, title text, body text, priority. Exposes title, text, bigText, category, priority, key, and more. Requires notification access.
Battery & power
3- Battery State
battery.stateBattery level or charging state changes.
Level threshold, direction (rising / falling / any), low-battery, hysteresis.
- Charging Type
battery.charging_typeA charger connects or disconnects.
Charger type (USB / AC / wireless / dock), connected / disconnected.
- Battery Temperature
battery.temperatureTemperature crosses a threshold.
Above / below, °C threshold.
Connectivity
7- Network Connectivity
connectivity.stateWi-Fi or mobile data connectivity changes.
Per-network connect / disconnect, SSID pattern.
- Wi-Fi SSID
connectivity.wifi_ssidYou connect to or leave a specific network.
Exact SSID, connected / disconnected. Requires location.
- Network Type
connectivity.network_typeNetwork type changes (2G / 3G / 4G / 5G / Wi-Fi).
Types, connect / disconnect.
- Airplane Mode
connectivity.airplaneAirplane mode is toggled.
Enabled / disabled / changed.
- VPN State
connectivity.vpnA VPN connects or disconnects.
Optional VPN name filter.
- Bluetooth Device
connectivity.bluetooth_deviceA specific Bluetooth device connects or disconnects.
Device MAC, type. Requires Bluetooth.
- Hotspot State
connectivity.hotspotYour hotspot is enabled or disabled.
Enabled / disabled / changed.
Device & system
8- Device State
device.stateScreen turns on or off, or the device is unlocked.
Screen on / off, user unlock.
- Headset Plugged
device.headsetHeadphones connect or disconnect.
Wired / Bluetooth / any. Bluetooth needs permission.
- NFC Tag Scanned
device.nfcAn NFC tag is scanned.
Tag-ID and content filters (wildcards). Requires NFC.
- Do Not Disturb
device.dndDND mode changes.
Enabled / disabled / changed. Requires DND access.
- Media Button
device.media_buttonA media button is pressed.
Play / pause / next / previous.
- Device Boot
system.bootCompletedThe device finishes booting.
- Alarm Triggered
system.alarmA device alarm fires.
All or specific alarms.
- Clipboard Changed
clipboard.changedClipboard content changes.
Optional text filter.
Schedule & time
1- Scheduled Time
time.scheduleA schedule fires.
Intervals, specific times, days of week, cron expressions, timezone. Exact timing needs alarm access.
Location
1- Geofence
location.geofenceYou enter, exit, or dwell in an area.
Multiple geofences (lat / lng / radius, enter / exit / dwell). Requires location + background location.
Apps
1- App Opened / Closed
app.foregroundAn app comes to or leaves the foreground.
App selection, opened / closed, minimum foreground time. Requires usage access.
Phone & calendar
2- Phone Call
phone.callA call event occurs (incoming / outgoing / answered / ended / missed).
Number / contact filters, minimum duration. Requires phone state (+ contacts for names).
- Calendar Event
calendar.eventA calendar event starts or ends, or a reminder fires.
Minutes-before, calendar and title filters. Requires calendar.
Sensors
5- Physical State
sensor.physical_stateThe phone's orientation or motion changes (flat, face-down, shaken, and so on).
State, sensitivity, debounce.
- Proximity Sensor
sensor.proximitySomething approaches or leaves the proximity sensor.
Near / far / changed, sensitivity.
- Device Picked Up
sensor.pickupThe device is picked up.
Sensitivity.
- Light Level
sensor.lightAmbient light crosses a threshold.
Bright / dark, threshold, sensitivity.
- Step Counter
sensor.stepsA step-count milestone is reached.
Threshold, daily reset. Requires activity recognition.
Chat
1- Flowroid Chat
flowroid.chatA message is sent in Flowroid's in-app chat.
Optional target-flow filter.
Inbound & on demand
2- Webhook Received
http.receivedAn external system calls this flow’s own URL on the device.
The trigger’s panel shows the full URL and a QR code, with a per-hook token on by default, an HTTP-method filter, a rate limit and a test request. The parsed body arrives as
{{event.body.*}}. Reachable from the network only once LAN access is on. - Manual
flow.manualYou start the flow yourself, from outside the app.
A Quick Settings tile, a launcher shortcut, a home-screen widget button, a notification action, or the HTTP API.
Action catalog
Flowroid ships 45+ actions. Each action's outputs are available to later actions via template expressions.
Android 10+ radio note
Google restricts apps from silently toggling Wi-Fi (and some other radios) on Android 10 and newer. On those versions the Wi-Fi action may open a system panel for confirmation rather than switching silently. Templates that rely on this carry an honest in-app limitation note.
HTTP & integrations
1- HTTP Request
http.requestSends an HTTP request to an external endpoint.
URL, method, headers, body, content type, timeout. Outputs
statusCode,headers,body,latency.
Notifications
2- Post Notification
notification.postPosts a notification.
Title, text, big text, channel, priority, ongoing, auto-cancel.
- Cancel Notification
notification.cancelCancels a notification.
By id (own posts) or by key (any notification, via notification access).
Device control
12- Set Volume
device.volumeSets or mutes a volume stream (media / ring / notification / alarm / system).
- Set Ringer Mode
device.ringer_modeNormal / vibrate / silent.
- Set Brightness
device.brightnessManual level or auto.
Needs Modify settings.
- Set Screen Timeout
device.screen_timeoutSets the screen timeout.
Needs Modify settings.
- Control Screen State
device.screenStateScreen on / off, or lock the device.
- Flashlight
device.flashlightOn / off / toggle with brightness.
Needs camera.
- Vibrate
device.vibrateDuration or custom pattern.
- Set Auto Rotate
device.auto_rotateOn / off.
Needs Modify settings.
- Dark Mode
device.darkModeOn / off / toggle.
Needs Modify settings.
- Keep Screen Awake
device.keep_awakeHolds a wake lock for a duration.
- Toggle Wi-Fi
device.wifiOn / off / toggle.
Behaviour limited on Android 10+ — see the radio note above.
- Toggle Bluetooth
device.bluetoothOn / off / toggle.
Needs Bluetooth.
Audio & media
3- Play Sound
audio.playPlays an audio file on a chosen stream.
- Text to Speech
audio.ttsSpeaks text (pitch, rate, language).
- Media Control
media.controlPlay / pause / next / previous / stop.
Connectivity
3- Connect Bluetooth
connectivity.bluetooth_connectConnects to a device by MAC (A2DP / HFP / HSP).
- Toggle Airplane Mode
connectivity.airplaneOn / off / toggle.
Needs Modify settings.
- Toggle Hotspot
connectivity.hotspotOn / off / toggle with optional SSID and password.
Apps & system
4- Launch App
app.launchLaunches an app, or opens a URL or intent.
- Kill App
app.killTerminates a running app.
- Send Intent
system.intentSends an arbitrary Android intent (action, package, class, data, extras).
- Set Clipboard
system.setClipboardWrites text to the clipboard.
Phone & chat
2- Make Phone Call
phone.callDials a number.
Needs Make calls.
- Send Chat Response
chat.respondSends a message in Flowroid's in-app chat.
Files
7- Read File
file.readReads file contents (encoding, max lines).
- Write File
file.writeWrites or appends content.
- Copy File
file.copyCopies a file.
- Move File
file.moveMoves or renames a file.
- Delete File
file.deleteDeletes a file (recursive for directories).
- Create Directory
file.mkdirCreates a directory.
- List Directory
file.listLists directory contents with an optional filter.
Flow control & logic
11- Delay
flow.delayPauses for a duration.
- If / Else
flow.ifElseBranches into nested actions based on a condition group.
- Loop
flow.loopRepeats nested actions (forEach / times / while).
- Call Sub-Flow
flow.callCalls another flow with an input object.
- Set Variable
flow.setVariableSets a flow- or global-scoped variable.
- Clear Variable
flow.clearVariableClears a variable.
- Math Operation
flow.mathadd / subtract / multiply / divide / modulo / power.
- String Operation
flow.stringuppercase / lowercase / trim / replace / split / concat / substring.
- Array Operation
flow.arraypush / pop / shift / unshift / filter / map / join.
- Log
flow.logWrites a message to the debug log.
- Stop Flow
flow.stopStops execution with an optional reason.
Conditions
Conditions let a flow decide whether to proceed, or which branch to take in an If / Else. Each condition compares a left value (usually a template expression) against a right value using an operator.
Operators
Equality & text
| Operator | Meaning |
|---|---|
| EQUALS | Exact match (case-sensitive) |
| NOT_EQUALS | Not equal |
| CONTAINS | Substring present (case-insensitive) |
| NOT_CONTAINS | Substring absent |
| STARTS_WITH | Prefix match (case-insensitive) |
| ENDS_WITH | Suffix match (case-insensitive) |
| MATCHES_REGEX | Matches a regular expression |
Numeric
| Operator | Meaning |
|---|---|
| GREATER_THAN | Left > right |
| GREATER_THAN_OR_EQUALS | Left ≥ right |
| LESS_THAN | Left < right |
| LESS_THAN_OR_EQUALS | Left ≤ right |
Lists
| Operator | Meaning |
|---|---|
| IN | Value is in a list (JSON array or comma-separated) |
| NOT_IN | Value is not in the list |
Presence
| Operator | Meaning |
|---|---|
| IS_EMPTY | Empty or null |
| IS_NOT_EMPTY | Has a value |
| IS_NULL | Null or missing |
| IS_NOT_NULL | Present and non-null |
Time & date
| Operator | Meaning |
|---|---|
| TIME_BEFORE | Current time is before HH:mm |
| TIME_AFTER | Current time is after HH:mm |
| TIME_BETWEEN | Current time is within HH:mm-HH:mm (handles overnight ranges) |
| DAY_OF_WEEK_IN | Today is one of the listed days |
How values are compared
Numeric operators try a numeric comparison first and fall back to string comparison if the values aren't numbers. List operators accept either a JSON array (["a","b"]) or a comma-separated string (a, b).
Combining conditions
Conditions group into AND / OR sets, and groups can nest arbitrarily deep for complex logic. An empty condition group passes (evaluates to true).
AND
├── {{event.sender}} EQUALS "+15551234567"
└── OR
├── {{event.body}} CONTAINS "urgent"
└── {{event.body}} CONTAINS "important"Variables & template expressions
Scopes
| Scope | Persistence | Writable | Use for |
|---|---|---|---|
| Global | Persists across flows and app restarts | Yes | Counters, shared state, settings |
| Flow | In-memory, single execution | Yes | Temporary values, loop indices |
| Event | Read-only during execution | No | The trigger's payload |
| Device | Real-time, read-only | No | Live device state |
| Secret | Encrypted at rest, read-only in expressions | No | API keys, tokens, passwords |
Template expressions
Anywhere a field accepts dynamic input, use {{ ... }} expressions with dot-notation and array indexing:
{{event.sender}} Trigger event field
{{event.data.nested}} Nested field
{{event.items[0]}} Array index
{{global.counter}} Global variable
{{flow.temp}} Flow-scoped variable
{{previous.http.body}} Output of a previous action (by type)
{{prev[0].output.field}} Output of a previous action (by index)
{{device.battery.level}} Live device state
{{secret.api_key}} Secret value (read-only)Device variables
The device.* namespace exposes live state without needing a trigger:
- Battery —
device.battery.level,.charging,.status - Network —
device.network.connected,.type,.wifi - Screen —
device.screen.brightness - Android —
device.android.version,.release - Locale —
device.locale.language,.country - Time —
device.time.zone,.timestamp
Referencing a category without a property (e.g. {{device.battery}}) returns the whole object as JSON.
Secrets
Secret variables are encrypted at rest using AES-256-GCM with a key held in the device's hardware-backed Keystore (where available). Secret values are masked everywhere in the UI, are never written to logs, and are read-only inside expressions — a flow can use {{secret.api_key}} but cannot overwrite it.
Permissions
Flowroid only asks for the permissions needed by the features you actually use. They fall into two groups: standard runtime permissions (granted with a system dialog) and special-access permissions (granted on a dedicated Android settings screen).
On SMS & call logs
Flowroid intentionally does not request SMS (READ_SMS / SEND_SMS / RECEIVE_SMS), call-log, or call-screening permissions. These were removed to comply with Google Play policy. Phone-call triggers use only the basic phone-state permission.
Runtime permissions
| Permission | Enables | Notes |
|---|---|---|
NotificationsPOST_NOTIFICATIONS | Posting notifications and the foreground-service status notification. | Required on Android 13+ |
Phone stateREAD_PHONE_STATE | The Phone Call trigger (incoming / outgoing / answered / ended / missed). | No call-log access |
ContactsREAD_CONTACTS | Showing contact names in call triggers, filtering by contact. | Optional |
Make callsCALL_PHONE | The Make Phone Call action. | Optional, dialer flow only |
Fine locationACCESS_FINE_LOCATION | Geofence triggers, Wi-Fi SSID detection (required by Android for SSID). | — |
Background locationACCESS_BACKGROUND_LOCATION | Geofences that work while the app is in the background. | Android 10+. Shown only after an in-app disclosure explaining why |
BluetoothBLUETOOTH_CONNECT | Bluetooth device triggers, headset detection, Bluetooth toggle. | Android 12+ |
Activity recognitionACTIVITY_RECOGNITION | The Step Counter trigger. | Android 10+ |
CalendarREAD_CALENDAR | The Calendar Event trigger. | — |
Special-access permissions
These are granted through Android's settings, not a popup. Flowroid links you straight to the right screen. The Permissions screen shows everything at a glance, grouped by category, with grant status and one-tap actions; a Guided mode walks you through only the permissions that still need attention.
| Access | Enables | Where |
|---|---|---|
| Notification access | Notification triggers — reading notifications from other apps. | Settings → Special app access → Notification access |
| Usage access | The App Opened / Closed trigger (foreground app detection). | Settings → Special app access → Usage access |
| Modify system settings | Actions that change brightness, screen timeout, auto-rotate, dark mode. | Settings → Special app access → Modify system settings |
| Schedule exact alarms | Precise schedule and timed triggers. | Settings → Special app access → Schedule exact alarms (Android 12+) |
| Do Not Disturb access | The Do Not Disturb trigger and ringer / DND actions. | Settings → Special app access → Do Not Disturb access |
| Display over other apps | Launching apps from background triggers (e.g. after unlock). | Settings → Special app access → Display over other apps |
| Battery optimization exemption | Reliable background execution. | Settings → Battery → Battery optimization |
Keeping automations running
Android aggressively stops background apps to save battery, and some manufacturers are far more aggressive than others. To make sure your flows run when you expect them to:
- Exempt Flowroid from battery optimization. The single most important step. Settings → Apps → Flowroid → Battery → Unrestricted / Not optimized.
- Enable auto-start on Xiaomi, Oppo / Realme, Vivo / iQOO, OnePlus, Huawei / Honor, Asus, and similar. These brands block apps from starting after a reboot unless you allow auto-start in their own settings. Flowroid provides a shortcut to the relevant manufacturer screen.
- Grant notification access if you use notification triggers.
- Grant exact-alarm access if you use schedules and want minute-accurate timing.
Boot behaviour
When your device restarts, Flowroid's boot receiver restarts the foreground service (if auto-start is enabled) and resumes all enabled flows. Boot triggers fire after you first unlock the device, once encrypted storage becomes available — Flowroid does not run during the locked, pre-unlock phase.
Templates
Flowroid ships 63 ready-made templates spanning beginner to intermediate automations, including a set built around webhooks — the phone answering something else on your network. The Templates library is the shortest path to a first flow: pick one, adjust its times, places, apps and thresholds, and install it. It arrives as an ordinary flow on the same canvas, with nothing held back. A sampling of what's included:
- Silent at Night
Go silent at bedtime on selected days.
- Low Battery Alert
Notify when the battery drops below a threshold.
- Wi-Fi at Home
Manage Wi-Fi on geofence arrival.
- Flip to Silence
Silence the phone when placed face-down.
- Headphones Auto-Play
Launch music and set volume when headphones connect.
- NFC Office Mode
Tap a tag to switch to work mode.
- Auto Dark Mode at Sunset
Schedule-based dark mode.
- Pocket Mode Protection
Lock the screen when pocketed.
- Meeting Auto-Silence
Silence during calendar events.
- Battery Overheat Warning
Alert on high battery temperature.
- Auto TTS Notification Reader
Read notifications aloud.
- Media Pause on Call
Pause media on an incoming call, resume after.
- File Backup on Charge
Back up a file when charging.
…and many more across power, connectivity, sensors, and productivity.
Honest limitations
Some templates depend on capabilities Android restricts on newer versions or specific manufacturers (for example, silently toggling Wi-Fi on Android 10+, or force-closing apps). Those templates display a clear limitations note in their detail screen describing exactly what will and won't work on your device, so there are no surprises.
Import & export
Every flow can be exported to a portable file and re-imported on the same or another device — handy for backups, sharing, or moving between devices. Import / export works entirely with local device storage: no account or cloud required. (Flows can also be exported and imported through the API server.)
The embedded HTTP API server
Flowroid can run an embedded HTTP server directly on your device, turning your phone into an automation endpoint that external systems call. The device is the server — your computer, home-automation hub, or another phone connects to the phone.
Security model
The API server is off by default and built secure-by-default:
- Localhost-only by default. It binds to
127.0.0.1and is unreachable from the network until you explicitly enable the Enable LAN access toggle (which rebinds to0.0.0.0and shows a clear warning). - Authentication required. All protected routes require an API key or a JWT bearer token. The signing secret is stored in the hardware-backed Keystore; if that's unavailable the server refuses to start rather than fall back to a guessable secret.
- Scoped access. API keys carry fine-grained scopes (
flows:read,flows:write,flows:execute,variables:read,webhooks:write) so you grant only what each integration needs. - CORS closed by default. No browser origins are allowed unless you add them to an allow-list; wildcard origins are rejected.
- Request body cap of 1 MiB and configurable rate limiting.
- Secrets never leave in plaintext. Secret variables are returned masked; revealing a value requires a separate dedicated scope.
- SSRF protection on outbound HTTP actions (loopback, link-local, and private ranges are blocked by default).
- Optional HTTPS / TLS with a self-signed certificate you can export, and HMAC-SHA256 signature verification for inbound webhooks.
Authentication flow
Exchange an API key for a short-lived JWT, or authenticate per-request with the key directly (X-Api-Key: fd_live_xxxx).
# Exchange an API key for a short-lived JWT
curl -X POST http://<device-ip>:8080/api/v1/auth/token \
-H "Content-Type: application/json" \
-d '{"apiKey":"fd_live_xxxxxxxxxxxxxxxx"}'
# → { "accessToken": "...", "refreshToken": "...", "expiresIn": 900 }Core endpoints
All endpoints are versioned under /api/v1.
| Group | Examples |
|---|---|
| Health & info | GET /api/v1/health, GET /api/v1 |
| Auth | POST /auth/token, POST /auth/refresh, GET /auth/me, GET /auth/scopes, API-key CRUD under /auth/apikeys |
| Flows | GET /flows, POST /flows, GET/PUT/PATCH/DELETE /flows/{id}, /flows/{id}/toggle, /execute, /duplicate, /executions, /export, POST /flows/import |
| Executions | GET /executions, GET /executions/{id}, GET /executions/{id}/logs |
| Device | GET /device plus /battery, /network, /storage, /memory, /screen, /locale, /apps, /sensors |
| Variables | GET /variables, GET/PUT/DELETE /variables/{name}, POST /variables/{name}/reveal |
| Webhooks | GET/POST /webhooks, GET/PATCH/DELETE /webhooks/{id}, plus the public trigger endpoint POST /api/v1/hooks/{path} |
| Discovery | GET /discovery/mdns, /devices, /capabilities (mDNS service advertisement) |
| TLS | GET /tls, certificate inspection / export / regeneration |
| WebSocket | ws://<device-ip>:8080/api/v1/ws for real-time execution events |
Run a flow remotely
curl -X POST http://<device-ip>:8080/api/v1/flows/<flow-id>/execute \
-H "X-Api-Key: fd_live_xxxx" \
-H "Content-Type: application/json" \
-d '{"input":{"reason":"manual run"},"sync":true}'Inbound webhooks
Create a webhook bound to a flow, then trigger it from any external system. The webhook can require no auth, an API key, a bearer token, or an HMAC-SHA256 signature:
BODY='{"event":"deploy","status":"green"}'
SIG=$(printf '%s' "$BODY" | openssl dgst -sha256 -hmac "your-secret" -hex | sed 's/^.* //')
curl -X POST http://<device-ip>:8080/api/v1/hooks/my-webhook \
-H "Content-Type: application/json" \
-H "X-Signature: sha256=$SIG" \
-d "$BODY"Live, interactive reference
The server publishes its own always-current OpenAPI spec and Swagger UI on the device: GET /openapi.json and /openapi.yaml for the machine-readable spec, GET /docs for interactive Swagger UI, and GET /redoc for the ReDoc viewer. Because these are generated from the running server, they are the authoritative, version-matched reference for your specific build.
The AI assistant
Ask in plain language and the assistant runs your flows and Flowroid's own device actions, showing you each step as it goes. Anything that changes your device asks first, spelling out exactly what will run.
What it can do
- Run Flowroid's device actions — flashlight, ringer, brightness, volume, Wi-Fi, notifications, text-to-speech and the rest of the catalog in Actions.
- List and run your flows, make HTTP requests to servers you own, work with files, and read or write global variables.
- Draft a flow for you. Describe an automation and it returns a review card you can read and keep without leaving the conversation; once it has actually run something for you, Save as flow turns that session into a reusable automation. In both cases the flow is saved disabled for you to review before anything runs on its own. The drafting surfaces are covered in Build with AI.
- Ask you a clarifying question when your request is ambiguous.
What it cannot do
The assistant has Flowroid's own action catalog and your flows, and nothing else. It cannot control other apps, tap buttons inside them, or read what is on your screen — Flowroid has no accessibility service, and no release of it does. It can launch an app or fire an Android intent, because those are ordinary Flowroid actions, but it cannot drive another app's interface.
You stay in control
- Confirmation before anything changes. An HTTP POST, a file write, a system intent, a device-state change — each pauses with a card showing exactly what will run. Allow it, deny it, or allow it for the session.
- Autonomous mode is optional and sits behind an explicit warning. Even then, blocked actions, your secret variables and the network safety blocklist still apply, and a bar shows it is on.
- Interrupted approvals fail closed. Close the app with a confirmation pending and that action is recorded as declined, never run later.
- Secrets stay secret. Secret variables are never readable by the assistant and are never sent with your message.
Talking to it
A microphone button sits next to the message box, and Flowroid can be set as your device's digital assistant so a long-press of the power button summons it. It is push-to-talk: there is no wake word and no background listening, and Flowroid never records or stores your audio. Speech is turned into text by your device's own recogniser.
Where it runs, and what leaves the phone
Answering a question needs a model, and the model is not on your phone. So when you send a message, that message and the conversation so far go to Flowroid's server and on to Google's Gemini API to be answered. We do not store it and we do not log it, and it is not used to train models. The Privacy Policy sets out the whole flow field by field.
Your automations are unaffected
Flows, triggers and actions run entirely on the device, with no connection and no AI involved — whether or not you have ever opened the assistant, and whatever your credit balance is. Never open it and nothing you type leaves the phone.
Two parts of the assistant never leave the device at all: the learned shortcuts that make repeated commands run instantly with no AI call, and the suggestions Flowroid draws from your own usage.
Running your own model
Point Flowroid at a model you host — Ollama, LM Studio, or any OpenAI-compatible server — under Settings → AI → Advanced. Requests then go to your address and nowhere else. It is free and unmetered: it does not touch your credit allowance, and it keeps the assistant working at a zero balance.
Plans & pricing
Flowroid is sold as one subscription that unlocks the whole app. There are no feature tiers and nothing is held back from a subscriber.
First 14 days
FreeEvery automation feature, from first launch, at no cost.
- Unlimited flows, and every trigger, action and condition
- The embedded HTTP API server, inbound webhooks, and the encrypted secret vault
- Geofence triggers and the map picker
- The curated template library and local import / export
- No payment method required. The trial cannot charge you, because we never hold your card details
- One trial per device, checked against Flowroid's licence server. Reinstalling does not start a second one
- The AI assistant is not included. Everything you automate is; the assistant is what the subscription pays for
Flowroid Pro
$4.99 per month$39.99 per year
US pricing. Google Play shows the price in your own currency, and confirms it before you are charged.
The whole app, plus the assistant. One plan, no tiers, no ads.
- Everything above, unlocked for as long as your subscription is active
- A monthly allowance of AI credits for the assistant, reset at the start of every billing period
- Renews automatically until you cancel. Cancel any time in Google Play → Subscriptions, or from Settings → License in the app; access runs to the end of the period you paid for
- Tied to your Google account, not to one handset. Restore it on any device you sign into
- Works offline on a signed licence, and renews that licence by itself when you reconnect
When the trial ends, Flowroid locks until you subscribe. Your flows are never deleted: they stay on the device and start running again the moment the app is unlocked.
If you bought Flowroid before
You keep it, permanently
Flowroid used to be a single one-time purchase. That purchase is honoured forever: it still unlocks the whole app, on every device signed into the Google account that bought it, and you will never be asked to pay again. It now also carries a standing monthly allowance for the AI assistant — smaller than the subscription's, and yours at no extra cost. If a new install does not recognise it, tap Restore purchase.
AI credits
Credits are what the assistant spends when it answers you. Pro includes a monthly allowance; it resets each billing period and does not roll over. If you use the assistant heavily you can buy top-up packs — currently $2.99, $6.99 and $19.99 — and purchased credits do not expire. They are spent only once the monthly allowance is gone.
Running out never stops your automations
Flows, triggers and actions run at a zero balance exactly as they do at a full one. Only the assistant pauses — and it comes back on its own when your monthly allowance resets, which costs nothing. Topping up is the option for not waiting, not the way out. Your own model keeps working either way, unmetered.
Privacy & security
- Automation is on-device, always. Flows run entirely on your phone. No account requirement, no cloud relay for flow execution, and no connection needed.
- The routine call that leaves is anonymous. Flowroid checks your trial and subscription status with its licence server. That request carries a one-way hash of a device identifier, never the raw identifier and never anything from your flows.
- The assistant is the one feature that sends what you type. Use it and your message and its context go to our server and on to Google's Gemini API to be answered; we do not store or log it, and it is not used to train models. Never open it and nothing you type leaves the phone. See The AI assistant and the Privacy Policy.
- Sensitive data stays local. Notification titles and text are never written to Flowroid's logs. Secret variables are encrypted at rest with a hardware-backed key and masked throughout the UI.
- The API server is opt-in, localhost-bound, and authenticated. Network exposure requires an explicit toggle; all protected routes require scoped credentials; CORS is closed by default.
- Outbound requests are guarded. The HTTP action blocks server-side request forgery against loopback, link-local, and private address ranges by default.
- No restricted permissions. Flowroid does not request SMS, call-log, or accessibility-service permissions.
- Honest capability disclosures. Where Android or a manufacturer restricts a capability, the relevant template or action says so plainly in-app.
The full Privacy Policy details exactly what each permission accesses and where the data goes.
Troubleshooting & FAQ
Does Flowroid need root, ADB, or a PC?
No. Flowroid runs on a stock, unrooted phone. Everything it does is built on ordinary Android runtime permissions and the special-access toggles Android exposes in Settings — notification access, usage access, modify system settings, exact alarms. You grant them in the app, and only the ones the flows you build actually need.
Does Flowroid work offline?
Yes. Triggers, conditions, actions, variables and execution history are all evaluated on the device, so flows run with no connection at all. The two parts that use a network are the ones you would expect: the HTTP Request action, which calls whatever endpoint you point it at, and the AI assistant, which sends your message to Flowroid’s AI service when you use it. Neither is required to automate anything.
Is Flowroid free?
Flowroid starts with a 14-day free trial of the whole app — every trigger, every action, the HTTP API server, all of it. After the trial it is $4.99 / month or $39.99 / year, billed through Google Play.
The trial does not include AI assistant credits; the assistant is part of the paid product. Automation itself never depends on credits.
Which Android versions and phones does Flowroid support?
Android 8.0 (API 26) and newer, on phones, tablets and Chromebooks that run Android apps. It is built against Android 14 APIs (target API 35).
Aggressive battery management on Xiaomi, Oppo, Vivo, OnePlus, Huawei and Asus devices is the one environmental caveat — those makers kill background work by default, and Flowroid has to be exempted for scheduled and background flows to fire on time. See Keeping automations running.
My flows stop running when the screen is off, or after a while.
Exempt Flowroid from battery optimization, and on Xiaomi, Oppo, Vivo, OnePlus, Huawei, and Asus devices enable auto-start. See Keeping automations running.
My automations don’t run after a reboot.
Make sure auto-start is enabled (especially on the manufacturers above) and that battery optimization is disabled. Flowroid resumes flows automatically once you unlock the device after boot.
Notification triggers stopped working after an update or reboot (Xiaomi / MIUI).
Some MIUI and HyperOS builds drop the notification-listener binding. Flowroid re-requests it automatically on boot and after updates; if a flow still doesn’t fire, toggle notification access off and on for Flowroid in Android settings.
My Wi-Fi, airplane, or radio toggle action doesn’t switch silently.
On Android 10+ Google restricts apps from changing these radios directly; the action may open a confirmation panel instead. This is an OS restriction, noted in-app on the affected templates.
My schedule fires a few minutes late.
Grant the “Schedule exact alarms” special access (Android 12+) and disable battery optimization for minute-accurate timing.
How do I actually build a flow?
Two ways, and the + button on the Flows screen holds both. Blank canvas opens the visual builder: a node canvas where you drop a trigger, drop the actions that should follow it, and wire them in order. Create with AI takes a sentence — “silence my phone during calendar events” — and drafts the flow, showing you the trigger, the conditions and the actions it means to build before anything is saved.
The Templates library is the third starting point and the quickest: install a ready-made automation, adjust its times and places, and it lands on the same canvas as an ordinary flow. There is no separate wizard — a flow is a flow however it got there. See Building flows.
Do I need the AI to build flows?
No. The visual builder is the whole product and it needs no connection, no credits and no assistant. Every trigger, every action, conditions, variables, loops, sub-flows and the HTTP API server are reachable by hand on the canvas.
Build with AI is a faster way in, not a different set of capabilities — it can only draft flows out of the same catalog you would have picked from yourself, and a flow it drafts is an ordinary flow you can open and change. Flows already built keep running at a zero credit balance.
Can I edit a flow the AI built?
Yes, completely. An AI-drafted flow is saved switched off so you can read it first, and it opens in the visual builder like any other — same nodes, same configuration forms, same validation. Nothing about it is locked, and nothing about it needs the assistant to run.
You can also go the other way and ask the assistant to change a flow you drew by hand. It shows you the revised version against the live one and leaves the live flow alone until you apply it, keeping its enabled state, its pin and its run history.
Can external apps control Flowroid?
Yes — enable the embedded API server. It’s localhost-only and authenticated by default; turn on LAN access only when you need network reach. See The embedded HTTP API server.
I bought Flowroid before — do I have to pay again?
No. Flowroid used to be sold as a single one-time purchase. That purchase is honoured permanently: it still unlocks the whole app, on any device signed into the Google account that bought it, and you will never be asked to subscribe. It also now carries a standing monthly allowance for the AI assistant, smaller than the subscription’s, which you did not have before.
If a fresh install does not recognise it, tap Restore purchase. See Plans & pricing.
What happens when I run out of AI credits?
Your automations keep running. Flows, triggers and actions never depend on credits — they run exactly the same at a zero balance as at a full one. Credits pay for the AI assistant, and nothing else.
The assistant itself pauses, and there are two ways back: wait for your monthly allowance to reset, which costs nothing and happens on its own, or buy a credit top-up if you would rather not wait. If you have configured your own model under Settings → AI → Advanced, the assistant keeps working through it regardless.
Can the assistant control my other apps?
No. Flowroid has no accessibility service, so it cannot tap buttons or read the screen inside other apps — and no release of it does. The assistant works with Flowroid’s own action catalog and the flows you have built. It can launch another app or send it an Android intent, because those are ordinary Flowroid actions, but it cannot drive that app’s interface.
Does Flowroid send SMS or read my texts or call log?
No. SMS and call-log capabilities are not part of Flowroid — these permissions were removed to comply with Google Play policy.
Where can I see why a flow did or did not run?
Open the flow’s execution history — each run records its trigger, the actions executed, their outputs, and any errors with logs.
Still stuck? Reach the maker directly — Flowroid has no telemetry, so the detail you include is all support has to go on.