Skip to main content

Documentation Index

Fetch the complete documentation index at: https://developer.trackpilots.com/llms.txt

Use this file to discover all available pages before exploring further.

๐Ÿงช Beta FeatureWebhook Simulations let you fire a real, signed test event to your endpoint โ€” no need to trigger a live desktop event.

๐Ÿ“Œ Overview

Webhook Simulations allow you to verify that your webhook endpoint is correctly receiving, parsing, and responding to Trackpilots events. When you run a simulation, Trackpilots:
  1. Builds a realistic sample payload for the selected event type
  2. Signs it with your webhookโ€™s secret key (identical to live delivery)
  3. POSTs it directly to your configured webhook URL
  4. Returns the HTTP status, response body, and latency back to you in the dashboard
๐Ÿ‘‰ Direct link: https://app.trackpilots.com/developer-tools/simulations

๐Ÿš€ How to Run a Simulation

  1. Open Developer Tools โ†’ Simulations in your Trackpilots dashboard.
  2. Select the Webhook Endpoint you want to test from the dropdown.
  3. Choose the Event Type to simulate โ€” only events registered for that webhook are shown.
  4. Click Send Test Event.
  5. View the result in the Simulation Result panel on the right.
โš ๏ธ Your webhook endpoint must be publicly accessible for the simulation to reach it.
Use ngrok or a similar tunnel to expose a local server during development.

๐Ÿ“Š Simulation Result Panel

After sending, the result panel shows:
FieldDescription
StatusHTTP status code returned by your endpoint (color-coded)
LatencyRound-trip time in milliseconds
Delivered / FailedWhether your endpoint returned a 2xx response
Delivery HeadersThe X-Webhook-Signature and X-Webhook-Timestamp sent
Sent PayloadThe exact JSON body that was posted to your endpoint
Endpoint ResponseThe raw response body returned by your server

๐Ÿ“ฆ Simulation Payload Structure

Simulation payloads are identical in structure to live events with one additional field โ€” "simulation": true โ€” so your server can distinguish test events from real ones if needed.

Activity Tracking

{
  "event": "desktop.activity_tracking.captured",
  "version": "v1",
  "agent": "desktop-agent",
  "simulation": true,
  "timestamp": 1746123456789,
  "data": {
    "organisation": { "organisationId": "3c90c3cc-0d44-4b50-8888-8dd25736052a" },
    "team": { "teamId": "3c90c3cc-0d44-4b50-8888-8dd25736052a" },
    "user": { "userId": "3c90c3cc-0d44-4b50-8888-8dd25736052a" },
    "activity": { "workMode": true }
  }
}

App Tracking

{
  "event": "desktop.app_tracking.captured",
  "version": "v1",
  "agent": "desktop-agent",
  "simulation": true,
  "timestamp": 1746123456789,
  "data": [
    {
      "organisation": { "organisationId": "3c90c3cc-0d44-4b50-8888-8dd25736052a" },
      "team": { "teamId": "3c90c3cc-0d44-4b50-8888-8dd25736052a" },
      "user": { "userId": "3c90c3cc-0d44-4b50-8888-8dd25736052a" },
      "tracking": {
        "trackingId": "e2fbd487-1ede-43e9-bd62-188da02d489f",
        "app": {
          "name": "Google Chrome",
          "type": "website",
          "category": "Unknown Category",
          "iconUrl": "https://www.google.com/favicon.ico",
          "domain": "google.com",
          "fullUrl": "https://www.google.com",
          "productivityStatus": "neutral"
        },
        "time": {
          "startDate": "2026-05-04T09:10:00.000Z",
          "endDate": "2026-05-04T09:10:20.000Z",
          "durationInSeconds": 20
        },
        "trackingMode": "online",
        "operatingSystem": "macos"
      }
    }
  ]
}

Screenshot Tracking

{
  "event": "desktop.screenshot_tracking.captured",
  "version": "v1",
  "agent": "desktop-agent",
  "simulation": true,
  "timestamp": 1746123456789,
  "data": [
    {
      "organisation": { "organisationId": "3c90c3cc-0d44-4b50-8888-8dd25736052a" },
      "team": { "teamId": "3c90c3cc-0d44-4b50-8888-8dd25736052a" },
      "user": { "userId": "3c90c3cc-0d44-4b50-8888-8dd25736052a" },
      "screenshot": {
        "screenshotId": "b774c86b-26e3-415f-b6d0-20a0a01b597c",
        "imageBuffer": "[simulation-placeholder: binary image buffer not included]",
        "app": {
          "name": "Google Chrome",
          "type": "website",
          "category": "Unknown Category",
          "iconUrl": "https://www.google.com/favicon.ico",
          "domain": "google.com",
          "fullUrl": "https://www.google.com",
          "productivityStatus": "productive"
        },
        "time": { "capturedAt": "2026-05-04T09:10:00.000Z" },
        "operatingSystem": "macos",
        "workType": "remote",
        "isIdle": false
      }
    }
  ]
}
๐Ÿ“ธ Screenshot imageBufferReal screenshot events include a raw binary image buffer.
Simulations send a placeholder string instead: "[simulation-placeholder: binary image buffer not included]".
Make sure your parser handles both gracefully.

๐Ÿ” Signature Verification

Simulation requests are signed exactly like live events using HMAC SHA-256. Your server receives:
X-Webhook-Signature: <hmac-sha256-hex>
X-Webhook-Timestamp: <unix-seconds>
Content-Type: application/json
Verification formula:
HMAC_SHA256( unix_timestamp + "." + raw_body_string, WEBHOOK_SECRET )
The result must match X-Webhook-Signature. See the Webhooks verification guide for the full implementation.

๐Ÿงช Testing Locally with ngrok

  1. Start your local webhook server (e.g. on port 3000)
  2. Expose it with ngrok:
ngrok http 3000
  1. Copy the generated HTTPS URL and set it as your Webhook URL in Trackpilots:
https://YOUR_NGROK_URL/webhooks/trackpilots
  1. Run a simulation โ€” the request will tunnel through ngrok to your local server.

โœ… What a Successful Simulation Looks Like

Status     200
Latency    312 ms
Result     โœ… Delivered
Your server should log:
โœ… Webhook verified โ€” event: desktop.app_tracking.captured | simulation: true
If you see 401 Invalid signature โ€” double-check that TRACKPILOTS_WEBHOOKS_SECRET_KEY in your environment matches the secret shown on your webhook in the dashboard. If you see 400 Missing signature โ€” make sure your server reads both x-webhook-signature and x-webhook-timestamp headers (lowercase).