Tracking and unsubscribe

Opens, clicks and unsubscribes are counted by Runearc itself, with signed links and no third party. Settings are per workspace.

How it works

When tracking is on, Runearc adds a 1 pixel image to the HTML for opens and rewrites links to a signed redirect for clicks. Both use tokens that identify the message and recipient; a forged token is rejected. Hits from link scanners, mail security gateways and preview bots are stored with is_bot: true and a reason, and never counted. The public routes are GET /t/o/{token} (the pixel), GET /t/c/{token} (a 302 to the original URL) and GET, POST /t/u/{token} (the unsubscribe page and the one click endpoint). They need no key.

Marketing mail (campaigns, sequences, or an email sent with the tag category set to marketing) also gets an unsubscribe link and a List-Unsubscribe header, is refused for unsubscribed recipients with recipient_unsubscribed, and honours the frequency cap. Transactional mail is never blocked by either.

Settings

curl -X PATCH https://api.runearc.com/v1/tracking/settings \
  -H "Authorization: Bearer $RUNEARC_API_KEY" \
  -H "Content-Type: application/json" \
  -d '{ "track_opens": true, "track_clicks": true,
        "frequency_cap": { "count": 3, "hours": 24 } }'
FieldTypeDescription
track_opensbooleanDefault true.
track_clicksbooleanDefault true.
unsubscribe_enabledbooleanDefault true. Adds the link and header to marketing mail.
strict_bot_filterbooleanDefault true. Flags more suspicious hits, such as several links clicked within seconds.
frequency_capobject | null{ "count": 1..1000, "hours": 1..8760 }: at most that many marketing emails per recipient in the window. null removes it. Default none.

GET /v1/tracking/settings reads them and PATCH /v1/tracking/settings changes the keys you send. Changing needs a key or role that manages domains.

Tracking domain

Links use a shared Runearc host by default. To put them on your own host, set a subdomain such as track.acme.com and add the CNAME it returns in cname_target, then verify.

RequestBodyReturns
GET /v1/tracking/domainnonehostname, status (pending or verified), cname_target, verified_at.
PUT /v1/tracking/domainhostnameThe domain, pending.
POST /v1/tracking/domain/verifynoneChecks the CNAME in live DNS. Verified, or tracking_cname_missing.
DELETE /v1/tracking/domainnone204. Back to the shared host.

Read what was counted

RequestQueryReturns
GET /v1/emails/{id}/trackingnoneopens, unique_opens, clicks, unique_clickers, unsubscribes, flagged_opens, flagged_clicks.
GET /v1/tracking/eventsmessage_id, contact_id, kind (open, click, unsubscribe), include_bots, limitdata: id, message_id, contact_id, recipient, kind, url, is_bot, bot_reason, created_at.

Totals over time, by campaign or by sequence are on Analytics.

CLI and MCP

runearc tracking show
runearc tracking set --opens on --clicks on --unsubscribe on --strict on --cap 3/24   # or --no-cap
runearc tracking domain-set track.acme.com
runearc tracking domain-verify
runearc tracking domain-delete
runearc tracking email eml_...

MCP tools: get_tracking_settings, update_tracking_settings and get_email_tracking.

Errors

CodeStatusMeaning and fix
invalid_frequency_cap400Use 1 to 1000 emails per 1 to 8760 hours, or null.
invalid_tracking_domain400Use a subdomain you control, such as track.acme.com, not the bare domain.
tracking_domain_taken409Another workspace uses that hostname.
tracking_cname_missing400The CNAME is not in DNS yet. Add it, wait, verify again.
recipient_unsubscribed400A recipient of a marketing email unsubscribed. Remove them, or send it as transactional.
frequency_cap_reached402A recipient reached the cap. Skip them or raise the cap.
A tracking link whose token is invalid answers 404 with plain text, and the pixel always answers a GIF, so neither reveals whether a token was valid.

Something unclear or wrong? The API answers every error with a fix, and so should these docs. Back to runearc.com