API

whatsmytraffic exposes public HTTP endpoints for four things: form submissions, a read-only analytics API, the passwordless auth service and the booking service.

Form submission

POST https://whatsmytraffic.com/f/YOUR-FORM-ID

Create a form in the dashboard (under a website) to get its ID. Point an HTML form at the endpoint, or POST to it from your own code.

HTML form Click to copy
<form action="https://whatsmytraffic.com/f/YOUR-FORM-ID" method="POST">
  <input name="email" type="email" required />
  <textarea name="message" required></textarea>
  <button type="submit">Send</button>
</form>

On success the visitor is redirected to a built-in confirmation page, or to the path given in the optional _redirect field.

Request

The body may be application/x-www-form-urlencoded, multipart/form-data or application/json. Every field is stored as part of the submission, except the control fields:

FieldPurpose
_gotchaHoneypot. Keep it hidden and empty. A filled value silently marks the submission as spam.
_redirectWhere to send the visitor after submit. Must be a relative, same-origin path (starts with a single /).

Response

  • If the request asks for JSON (Accept: application/json, or a JSON body), the endpoint returns 200 with {"ok":true}.
  • Otherwise it returns 303 and redirects to _redirect, or to a built-in confirmation page if no redirect was given.

Errors

StatusMeaning
404Unknown form ID
413Body larger than 256 KB
429Rate limit: more than 5 submissions per minute from one IP
400Body could not be parsed

AJAX

CORS is open and the OPTIONS preflight is handled, so you can submit with fetch and read the JSON result:

await fetch('https://whatsmytraffic.com/f/YOUR-FORM-ID', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({ email, message })
});

Side effects

Per form (configured in the dashboard), a successful, non-spam submission can trigger:

  • Webhook POST, ntfy push, notify emails.
  • Optional confirmation email to the address in the form's email field, sent from the website's SMTP or the instance mail.
  • If the beacon is loaded on the same page, a form_submit event with { form_id } in analytics.

Analytics API

Every website can have a share link (Websites tab, per website). The share link opens a public, read-only analytics page; append /data to it for a JSON feed of the same numbers. The token in the URL is also the API key: revoke it in the dashboard to cut access.

GET YOUR-SHARE-LINK/data

Query parameters

ParameterValuesDefault
range24h, 7d, 30d, allall
reshour, day, month (the allowed set depends on the range)per range
fieldscomma-separated, see belowall fields

fields selects which parts to return; parts you do not request are not even queried. Available: summary, series, top_pages, top_referrers, top_countries, top_browsers, flow (visitor paths as a staged node and link graph: source, landing page and the next two pages).

Response

{
  "website": "example.com",
  "range": "7d",
  "resolution": "day",
  "summary": { "pageViews": 1234, "visits": 567 },
  "series": [
    { "x": "2026-05-20T00:00:00.000Z", "pageviews": 120, "sessions": 80 }
  ],
  "top_pages": [ { "x": "/", "y": 540 } ],
  "top_referrers": [ { "x": "google.com", "y": 210 } ],
  "top_countries": [ { "x": "DE", "y": 430 } ],
  "top_browsers": [ { "x": "Chrome", "y": 690 } ]
}

Series timestamps are UTC. summary and series come from the same query, so requesting either one computes both.

Example

curl "YOUR-SHARE-LINK/data?range=30d&res=day&fields=summary,series"

A 404 means the share token is invalid or has been revoked.

Auth service

The auth service is a passwordless (magic-link) login you can add to your own site. Create an auth app in the dashboard (expand a website, open its Auth section) to get an app ID, and configure its redirect URLs and allowed origins. whatsmytraffic stores no end-user data: the session is a signed token that lives in the visitor's browser.

SDK

The simplest integration is the small browser SDK. It wraps every endpoint below and exposes window.wmtAuth:

Auth SDK Click to copy
<script defer src="https://whatsmytraffic.com/whatsmytraffic-auth.js"
        data-app-id="YOUR-APP-ID"></script>

wmtAuth.login(email) requests a magic link; wmtAuth.getSession() returns the signed-in user once they return from the link; wmtAuth.logout() clears the session.

Example: a sign-in page

A complete client-side integration: load the SDK, send the link, and switch between a signed-out and a signed-in view. The SDK captures the token from the URL fragment automatically when the user returns from the email.

Sign-in page Click to copy
<!-- 1. Load the SDK -->
<script defer src="https://whatsmytraffic.com/whatsmytraffic-auth.js"
        data-app-id="YOUR-APP-ID"></script>

<!-- 2. Two states: signed out and signed in -->
<div id="signed-out">
  <input id="email" type="email" placeholder="you@example.com" />
  <button id="send">Email me a sign-in link</button>
</div>
<div id="signed-in" hidden>
  Signed in as <span id="who"></span>
  <button id="logout">Sign out</button>
</div>

<!-- 3. Wire it up -->
<script>
  function render() {
    var session = wmtAuth.getSession();
    document.getElementById('signed-in').hidden = !session;
    document.getElementById('signed-out').hidden = !!session;
    if (session) document.getElementById('who').textContent = session.email;
  }
  addEventListener('load', render);

  document.getElementById('send').onclick = function () {
    wmtAuth.login(document.getElementById('email').value).then(function (res) {
      alert(res.ok ? 'Check your inbox for the link.' : 'Could not send the link.');
    });
  };
  document.getElementById('logout').onclick = function () {
    wmtAuth.logout().then(render);
  };
</script>

This is the visitor-facing half. To act on a session from your own backend (gate an API, store an order against the email), verify the token there as shown below.

Endpoints

EndpointPurpose
POST /a/APP-ID/requestBody { email, redirect? }. Emails a magic link valid for 15 minutes.
GET /a/APP-ID/callbackTarget of the magic link. Issues a session token and redirects to the configured URL, token in the URL fragment.
GET /a/APP-ID/verifyVerifies a session token (query ?token= or Authorization: Bearer) and returns its claims.
POST /a/APP-ID/logoutStateless acknowledgement. The token is dropped client-side.
GET /a/APP-ID/jwksPublic keys (JWKS) for verifying session tokens locally.

request, verify and logout are cross-origin: the request Origin must be in the app's allowed origins. callback is a top-level browser navigation.

Verifying a session

A session token is a signed JWT (ES256). Your backend can either ask /verify or check the signature locally against /jwks. The sub claim is the verified email address.

const res = await fetch(
  'https://whatsmytraffic.com/a/YOUR-APP-ID/verify',
  { headers: { Authorization: 'Bearer ' + sessionToken } }
);
const { ok, sub } = await res.json();

Sign-in links and sessions expire on their own; there is no server-side store. Delete the auth app in the dashboard to stop new sign-ins.

Side effects

Per auth app (configured in the dashboard), a sign-in can trigger:

  • Optional welcome email on the very first sign-in of each email address. Sent from the website's SMTP or the instance mail.
  • If the beacon is loaded on the same page as the SDK, two analytics events: auth_request when wmtAuth.login() is called, and auth_signin when the user returns through the magic link. Both carry { app_id }.

Booking service

Calendly-style scheduling. Create a booking page in the dashboard (expand a website, open its Bookings section) to configure duration, weekly availability, timezone and optional Google Calendar sync. Visitors book a slot; both sides get a confirmation email with an ICS calendar invite and a cancellation link.

SDK (modal)

The turnkey integration is the modal SDK: any element with data-wmt-booking opens the hosted booking page in an overlay. Programmatic API: wmtBooking.open() / wmtBooking.close().

Booking SDK Click to copy
<script defer src="https://whatsmytraffic.com/whatsmytraffic-booking.js"
        data-page-id="YOUR-PAGE-ID"></script>
<button data-wmt-booking>Book a call</button>

The hosted page also works standalone as a link target: https://whatsmytraffic.com/b/YOUR-PAGE-ID.

Endpoints (custom UI)

CORS is open on both endpoints, so you can skip the SDK entirely and build your own picker against the raw API:

EndpointPurpose
GET /b/PAGE-ID/slotsBookable slot starts as UTC ISO strings. Optional ?from=YYYY-MM-DD&to=YYYY-MM-DD (both inclusive, at most 31 days); default is today up to the page's booking horizon.
POST /b/PAGE-ID/bookBody { start, name, email, note? } where start is one of the returned slots. Returns 409 if the slot was taken in the meantime.

Slots response

{
  "ok": true,
  "timezone": "Europe/Berlin",
  "duration_min": 30,
  "slots": ["2026-08-12T07:00:00.000Z", "2026-08-12T07:45:00.000Z"]
}

Slots are instants: render them in the visitor's timezone. The page's own timezone and the slot duration are included for display.

Example: fetch and book

// 1. Fetch available slots (UTC instants; render them in the
//    visitor's timezone).
const res = await fetch(
  'https://whatsmytraffic.com/b/YOUR-PAGE-ID/slots?from=2026-08-01&to=2026-08-31'
);
const { slots } = await res.json();

// 2. Book one of them.
await fetch('https://whatsmytraffic.com/b/YOUR-PAGE-ID/book', {
  method: 'POST',
  headers: { 'Content-Type': 'application/json' },
  body: JSON.stringify({
    start: slots[0],
    name: 'Jane Doe',
    email: 'jane@example.com',
    note: 'Optional note'
  })
});

Errors

StatusMeaning
404Unknown or disabled booking page
409Slot no longer available (book)
429Rate limit (60 slot queries per minute, 5 booking attempts per 10 minutes, per IP)
502Google Calendar temporarily unavailable; availability is withheld instead of risking double bookings

Side effects

  • Confirmation emails with an ICS invite (METHOD:REQUEST) to the booker and the owner; cancellations send METHOD:CANCEL so calendars remove the event.
  • With Google Calendar connected, busy times block slots and bookings create events in the configured calendar.
  • If the beacon is loaded next to the SDK, two analytics events: booking_open and booking_confirmed.