Workflowy publishes an Apple Shortcut for capturing without opening the app. There isn’t an official Android equivalent, but you can build one in about ten minutes using the Workflowy API and a free app. No server, no Zapier subscription, no middleman.
The result: an icon on your home screen. Tap it, type, done. Plus a share-sheet entry so you can send selected text from any app straight into Workflowy.
The three shortcuts
| Journal | Inbox | To-do | |
|---|---|---|---|
| Lands in | today’s calendar node | your inbox | today’s calendar node |
| Node type | bullet | bullet | checkbox |
| Prompts | text | text | date picker, then text |
| Carries a timestamp | yes | no | no |
Journal is for rapid logging – timestamped bullets building a chronological record of the day. Inbox is a holding pen; what matters is that the thing got caught, not when. To-do captures a task with a real due date attached.
I’ve duplicated the shortcuts instead of trying to route them in the config - I’m not a programmer but I’m sure this is possible. This means three icons with zero decision cost when you want to capture.
What you need
- HTTP Request Shortcuts by Waboodoo – free, open source, no ads. Available on the Play Store and F-Droid.
- A Workflowy API key from Log in to Workflowy (log in first).
A note on the key: it has full read/write/delete access to your entire outline. It lives on your phone in the app. That’s fine for a personal device, but be careful if you ever export your shortcuts config to share it – the key is in there in plaintext.
Step 1 – Test the API
Optional, but it takes thirty seconds and rules out half the things that can go wrong. From any terminal:
bash
curl -X POST https://workflowy.com/api/v1/nodes \
-H "Content-Type: application/json" \
-H "Authorization: Bearer YOUR_API_KEY" \
-d '{"parent_id": "inbox", "name": "Hello from curl", "position": "bottom"}'
If that lands in your Workflowy inbox, the rest is just wiring.
Step 2 – Create the three variables
In the Request body section of the shortcut, tap the {} icon. That opens a Variables panel to define these, with an Edit global variables link at the bottom. Create and edit from there without leaving the screen, then tap a variable to insert it at the cursor.
Variables are global across all your shortcuts.
| Key | Type | Used by |
|---|---|---|
capture |
Text Input | all three |
ts |
Static Variable | journal only |
date_input |
Date Input | to-do only |
Each variable’s editor has Basic Settings at the top and Advanced Settings below.
capture (Text Input)
| Field | Value |
|---|---|
| Name | capture |
| Dialogue Title | Your prompt, e.g. “What’s the thought?” |
| Multiline | Your call – see below |
| Remember value | Off |
| JSON encode | On |
| Allow Receiving Value from Share Picker | On |
JSON encode: Set to On because an apostrophe, quote mark or line break can break the JSON body and result in a 400. With it on, the app escapes these values.
Allow Receiving Value from Share Picker is what makes the share sheet work. It’s near the bottom of Advanced Settings.
Multiline is worth turning on for the journal shortcut. The API nests multi-line text automatically – first line becomes the parent bullet, subsequent lines become children – so a multiline prompt gets you structured captures for free. Leave it off if you’d rather have a single-line box that submits faster.
ts (Static Variable)
| Field | Value |
|---|---|
| Name | ts |
| Value | leave empty |
| Treat value as secret | Off |
| URL encode | Off |
| JSON encode | Off |
The value is overwritten by a pre-execution script (see below) every time the journal shortcut runs, so whatever sits in the Value field doesn’t matter.
date_input (Date Input)
| Field | Value |
|---|---|
| Name | date_input |
| Dialogue Title | e.g. “Due date” |
| Date Format | yyyy-MM-dd |
| Remember value | Off |
| URL encode | Off |
| JSON encode | Off |
Step 3 – Settings common to all three
Add a new HTTP Shortcut. These are identical every time, so set it up once and duplicate for the other shortcuts.
Basic request settings
| Setting | Value |
|---|---|
| Method | POST |
| URL | https://workflowy.com/api/v1/nodes |
Authentication
| Setting | Value |
|---|---|
| Type | Bearer authentication |
| Token | your Workflowy API key |
Request body / parameters
| Setting | Value |
|---|---|
| Request Body Type | Custom Text |
| Content-Type | application/json |
Content-Type has its own field on this screen – no need to add it as a manual request header.
Response handling – set “On success” to show a toast. Confirmation without a full-screen window covering your phone.
The body editor gives you a { } [ ] : " shortcut row and a Format button that pretty-prints and validates the JSON. Use Format; it catches typos immediately.
Save, then long-press the shortcut to place it on your home screen.
Shortcut 1 – Journal
Timestamped bullet into today’s calendar node. One prompt.
Scripting → Run before Execution:
js
const d = new Date();
const p = n => String(n).padStart(2, "0");
setVariable("ts", `${p(d.getHours())}:${p(d.getMinutes())}`);
Hours and minutes only. getHours() reads device local time, so timezones handle themselves. Don’t use toISOString() – that returns UTC and will be wrong unless you happen to live in London in winter.
Leave Run on Success and Run on Failure empty. The toast is all the confirmation you need.
Request body:
json
{
"parent_id": "today",
"name": "{ts} – {capture}",
"position": "bottom"
}
No layoutMode means a standard bullet. "today" creates the calendar node on demand, so there’s nothing to set up in Workflowy first. The date is implied by where the bullet lands, which is exactly why this only needs the time.
Prefer the timestamp out of the way? Put it in a note instead:
json
{
"parent_id": "today",
"name": "{capture}",
"note": "{ts}",
"position": "bottom"
}
Timestamp variations
Seconds:
js
setVariable("ts", `${p(d.getHours())}:${p(d.getMinutes())}:${p(d.getSeconds())}`);
12-hour:
js
const h = d.getHours();
setVariable("ts", `${h % 12 || 12}:${p(d.getMinutes())}${h < 12 ? "am" : "pm"}`);
Shortcut 2 – Inbox
Duplicate the journal shortcut, then strip it back. Plain bullet into your inbox, no timestamp.
Scripting: clear the Run before Execution box entirely.
Request body:
json
{
"parent_id": "inbox",
"name": "{capture}",
"position": "bottom"
}
Do both. Clearing the script but leaving {ts} in the body is the trap described above – the variable still resolves, to a stale value from your last journal entry. Body and script come out together.
Shortcut 3 – To-do
Checkbox item in today’s node, carrying a real Workflowy date object. Two prompts: date picker, then text.
Scripting: none.
Request body:
json
{
"parent_id": "today",
"name": "{capture} [{date_input}]",
"layoutMode": "todo",
"position": "bottom"
}