HyperTrackDocs
WebhooksWorkers

Outage Codes

The outage_code and outage_category values in outage webhooks, how to detect permission revocation, and how outages open and close.

The data.outage_code field on every outage_started and outage_ended webhook is a machine-readable identifier of the outage reason.

The accompanying data.outage_category groups codes by what's responsible:

outage_categoryWhat it means
behaviouralCaused by worker action (denied permission, force-stopped app, airplane mode).
osCaused by the operating system (kill, suspend, crash).
adversarialAnti-fraud signal (mocked location, time tampering).
sporadicTransient hardware/environment issue (GPS unavailable).
reachabilityServer-side cannot reach the device (push failed, no token).

outage_codeoutage_labeloutage_categoryDescription
location_permissions_deniedLocation permission deniedbehaviouralWorker fully denied location permission. On iOS, a denial also sends location_permission_imprecise.
location_permission_when_in_use_backgroundBackground location permission not grantedbehaviouralWorker granted "When In Use" only — app cannot start tracking from background.
location_permission_impreciseLocation imprecisebehaviouralWorker downgraded to approximate location instead of precise. On iOS, a denial also sends location_permissions_denied.
location_permission_not_determinedLocation permission unknownbehaviouralPermission state is unset (e.g. "Allow Once" reset, or never prompted).
location_permission_restrictedLocation permission restrictedbehaviouralPermission blocked by Screen Time, parental controls, or MDM policy.
location_services_disabledLocation services disabledbehaviouralPhone-level Location Services toggle is off.
location_unavailableLocation unavailablesporadicApp could not get a fresh GPS fix (signal lost, indoors, airplane mode, etc.).
location_unavailable_provisional_authorizationLocation unavailable authreachabilityApp requested Always permission without first asking When In Use; iOS limits authorization.
location_mockedLocation mockedadversarialA mock-location app was active on the device.
airplane_mode_detectedDevice in airplane modebehaviouralWorker enabled airplane mode.
notifications_permission_deniedNotification permission deniedbehaviouralNotifications disabled — push-driven start cannot be delivered.
foreground_service_deniedForeground service start prohibitedbehaviouralAndroid blocked tracking from starting in the background. Opening the app clears it.
tracking_service_terminatedTracking service terminatedbehaviouralApp was force-stopped by worker or killed by OS battery management.
sdk_killed_by_userApp killed by userbehaviouralWorker swiped the app away or used "Clear all".
sdk_killed_permission_changeApp killed by permission changebehaviouralWorker revoked a permission mid-tracking and the OS killed the app.
sdk_killed_low_memoryLow memoryosOS killed the app to reclaim memory.
sdk_killed_crashedApp crashedosApp crashed unexpectedly.
sdk_killed_excessive_resource_usageApp killed — excessive resource usageosOS killed the app for using too much CPU, battery, or memory.
sdk_killed_app_not_responsiveApp killed for being unresponsiveosOS killed the app because it stopped responding (ANR-style).
sdk_killed_suspendedApp suspendedosOS suspended app execution while device was idle or locked.
storage_unavailableStorage unavailablebehaviouralDevice storage is full; app cannot persist or send tracking data.
push_notification_failedPush notification failedreachabilityServer sent a push to start tracking but it didn't reach the device.
push_token_missing_to_start_trackingPush token missingreachabilityPush notification service didn't supply a messaging token to the app.

Detecting permission revocation

To detect when a worker no longer has location permission to track, watch for an outage_started webhook where data.outage_category is behavioural and data.outage_code is one of:

  • location_permissions_denied
  • location_permission_when_in_use_background
  • location_permission_imprecise
  • location_permission_not_determined
  • location_permission_restricted
  • location_services_disabled
  • foreground_service_denied (Android)
  • sdk_killed_permission_change (Android)

To know when the worker has resolved the issue, wait for the next outage_ended on the same device. Do not match it by outage_code. See How outages open and close.

How outages open and close

The platform keeps one open outage per device. Use these rules to pair outage_started and outage_ended webhooks:

  • One open outage per device. An outage_started with a different outage_code replaces the open outage. The platform does not send an outage_ended for the outage that it replaced.
  • One outage_ended closes all open outages. The platform sends outage_ended one time, when the device sends a location again. Its outage_code is the code of the most recent outage_started. When you get it, close every open outage on that device.
  • A repeated code is the same outage. An outage_started with the same outage_code while the outage is open means that the SDK reported the condition again. It is the same outage. Do not open a second one.
  • iOS sends two codes for a denial. When the worker denies location on iOS, the SDK reports location_permission_imprecise and location_permissions_denied within milliseconds, as two outage_started webhooks. The platform does not send a webhook when precise location is available again. The single outage_ended closes both.

Example: iOS worker denies location, then allows it again

These three payloads arrive as separate webhooks; they are shown here in one array. The payloads are shortened: location, outage_label, outage_description, and version are left out. The worker denies location. 17 ms later the second code arrives. When the device tracks again, one outage_ended arrives with the most recent code, location_permissions_denied. It closes both outages.

[
  {
    "type": "worker",
    "device_id": "AB930CCD-50A9-4ECA-8758-D7CB09058606",
    "data": {
      "value": "outage_started",
      "outage_category": "behavioural",
      "outage_code": "location_permission_imprecise"
    },
    "recorded_at": "2024-11-28T12:45:00.000Z",
    "worker_handle": "ram@123"
  },
  {
    "type": "worker",
    "device_id": "AB930CCD-50A9-4ECA-8758-D7CB09058606",
    "data": {
      "value": "outage_started",
      "outage_category": "behavioural",
      "outage_code": "location_permissions_denied"
    },
    "recorded_at": "2024-11-28T12:45:00.017Z",
    "worker_handle": "ram@123"
  },
  {
    "type": "worker",
    "device_id": "AB930CCD-50A9-4ECA-8758-D7CB09058606",
    "data": {
      "value": "outage_ended",
      "outage_category": "behavioural",
      "outage_code": "location_permissions_denied"
    },
    "recorded_at": "2024-11-28T12:45:17.000Z",
    "worker_handle": "ram@123"
  }
]