n8n
Make Zippy a step in your n8n automations — create links mid-workflow, and start a workflow when a tap ACTUALLY opened someone's native app. Two official nodes, plus an HTTP Request recipe that works today.
n8n + Zippy
Most link tools give n8n a node that can tell you a click happened. Zippy's trigger tells you what happened next — whether that tap reached the person's real native app, got trapped in an in-app browser, or broke outright.
That's a branch nobody else can express: if the last twenty taps on this link came back
app.browser, swap the destination and DM me.
The nodes aren't installable yet — we haven't published them
@zippy/n8n-nodes-zippy is not on npm. n8n's Settings → Community nodes dialog
can't find it, and npm install @zippy/n8n-nodes-zippy resolves to nothing. The package is
built, tested (47 tests, including a live check of every route against the API itself) and
behaves exactly as described below — publishing it is the remaining step, and it's a founder
call that hasn't been made. This page gets the one-line install the day it lands.
In the meantime the HTTP Request recipe below works right now, on any n8n, with no node to install. It's the same API the nodes drive.
How do I use my link shortener in n8n today?
With n8n's built-in HTTP Request node against the Zippy API. No community
node, no install — Zippy's API is a Legend power, so you need a zip_ key from
Settings → API keys.
1. Store the key once. In n8n, create a Header Auth credential:
| Field | Value |
|---|---|
| Name | Authorization |
| Value | Bearer zip_your_key_here |
2. Add an HTTP Request node wherever your workflow needs a link:
| Field | Value |
|---|---|
| Method | POST |
| URL | https://api.zipthe.link/v1/links |
| Authentication | Generic → Header Auth → the credential above |
| Body (JSON) | {"url": "{{ $json.destination }}", "tags": ["n8n"]} |
3. Use {{ $json.shortUrl }} downstream. The response hands back the finished URL —
nothing to assemble from slug and hostname.
Every /v1 route is fair game from the same node: GET /v1/links/{id}/stats for app-open
outcomes, GET /v1/links/{id}/ab-stats for per-variant results,
PUT /v1/bio/blocks to rebuild a bio page. The
API reference lists all of them; rate limit is 120 requests per minute per
key.
How do I start an n8n workflow when someone opens my app?
This is the part worth building a workflow around, and it also works today — with n8n's Webhook node and a Zippy webhook subscription.
- Add a Webhook node (method
POST) and copy its production URL. It must behttps://and publicly reachable — Zippy refuses a loopback or private-range callback, because a registered webhook is a request our API makes. Local n8n needsWEBHOOK_URLset to a public address, or a tunnel. - Register that URL in Zippy — dashboard Webhooks, or
POST /v1/webhooks— subscribed toapp.opened,app.browserandapp.broken. Zippy shows the signing secret exactly once; store it. - Verify the signature before you trust the delivery. The webhook URL is public, so the
x-zippy-signatureHMAC is the only thing standing between your workflow and anyone who can send a POST. Turn on Raw Body on the Webhook node and check the HMAC in a Code node — the exact recipe is in the webhooks docs. - Branch on the event with an IF or Switch node.
Each delivery is the standard envelope:
sourceApp is the in-app browser the tap escaped from; platformKey is where it was
headed. Webhook subscriptions are a Legend feature, and a workspace can register up to
5.
Push, never poll
Don't build a Schedule trigger that calls /v1/links/{id}/stats every five minutes. An
idle webhook-driven workflow makes zero requests to the Zippy API, and no event falls
into the gap between two polls.
What will the official nodes add?
Two of them, and the second is the reason for the first.
Zippy Trigger replaces steps 1–3 above with a checkbox list. Activating the workflow
registers the subscription for you; deactivating removes it; editing the event list patches
the existing subscription instead of burning another of your five. It verifies the HMAC
itself, in constant time, and answers an unsigned or mis-signed delivery 401 without
starting the workflow. Defaults are ticked to the three app-outcome events, because that's
what the node is for.
It flattens the envelope one level so an IF node reads one field:
outcome is opened / browser / broken for the app.* events and null otherwise.
Zippy is the action node — the HTTP Request recipe, with dropdowns:
| Resource | Operations |
|---|---|
| Link | Create · Get Many · Update · Archive |
| Analytics | App-Open Outcomes · Click Events · A/B Variants · Workspace Overview |
| Bio Page | Get · Update · Set Blocks · Block App-Open Stats |
| Contact | Get Many · Delete |
One credential (Zippy API: your zip_ key plus your API's base URL), sent as
Authorization: Bearer. There's no OAuth variant, because /v1 never reads a session
cookie — and because a key resolves server-side to exactly one workspace, no parameter on
either node takes an org or workspace id. There is no shape of a call that reaches another
tenant.
utm, routing, ab, sched, password, pixelIds and hostname go through a single
Advanced (JSON) field rather than being modelled as node parameters — the API's own
validators are the source of truth for those shapes, and a hand-copied duplicate in a node
would drift out of date. An invalid field comes back as a 400 naming it.
How honest are the numbers I branch on?
Honest enough to be worth a warning. App-open rates are sampled estimates from an analytics pipeline, not an audit log:
- Branch on a trend or a whole-number rate, never a decimal difference between two runs.
appOpenRatecomes backnull, never0, when nothing has been measured yet. That means no data, not nobody opened it — a workflow that treats it as0will page you about silence.configured: falsemeans outcome collection isn't wired up upstream and every number in that response is a placeholder.
The opened/browser/broken split needs Hero or above; lower tiers get totals. Individual webhook deliveries are different — those are per-tap events, not a sample.
Archiving doesn't kill a link
Worth knowing before you automate it: Archive hides a link and frees a slot against your plan cap. It does not stop the link redirecting. A Zippy link resolves forever, by design, and no node, endpoint or workflow can change that. If you need a link dead, the honest answer is that Zippy can't do it.
FAQ
How do I use my link shortener in n8n?
Today, with the HTTP Request node pointed at https://api.zipthe.link/v1/links and a
Header Auth credential carrying Bearer zip_…. Read {{ $json.shortUrl }} off the response
and use it in the next step. An official community node is built but not yet published; when
it is, the same call becomes a Zippy → Link → Create dropdown.
Can n8n trigger on whether someone actually opened the app?
Yes, and only with Zippy. Subscribe an n8n Webhook node to app.opened, app.browser
and app.broken, and each tap arrives as its own event saying which of the three happened
on the device. Every other link tool's trigger fires on a click and stops there — a click
can't tell you whether the person landed in the real app or in a webview where they aren't
logged in.
Do I need to install anything to use Zippy with n8n?
No. The HTTP Request and Webhook nodes ship with every n8n, and Zippy's side is a plain HTTP API. The community node is convenience, not a requirement — and it isn't on npm yet anyway.
Why does Zippy reject my n8n webhook URL?
Because it isn't https:// on a publicly reachable host. http://localhost:5678/... and
private-range addresses are refused by design — registering a webhook means our API will
make requests to that URL, and the SSRF guard isn't negotiable. Set WEBHOOK_URL to your
public n8n address, or run n8n behind a tunnel.
Which plan do I need?
Legend for both the API key and webhook subscriptions. The app-open split in analytics responses needs Hero or above; below that you get totals. Creating links and reading your own numbers in the dashboard needs neither.
Will my n8n workflows break when the nodes get published?
No. The nodes call exactly the same /v1 routes your HTTP Request nodes call — they're a
nicer front end to the same API, not a different one. Migrating is optional.
Read more
- Blog: Your links should be a step in your automations — and n8n should know whether the app opened
- Changelog: The n8n nodes
- The Zippy API — every
/v1route, keys, rate limits. - Webhooks — the event stream underneath the trigger, and the HMAC recipe.
- MCP server — the same API, driven by conversation instead of a canvas.
- A/B split testing — per-variant app-open rates, readable from a workflow.
- ManyChat — the same escape-the-webview trick, inside a comment-to-DM flow.