Skip to Content
LoadersAirship

Airship Loader

The Airship loader pulls granular, row-level engagement events from Airship’s Real-Time Data Streaming (RTDS / “Connect”) feed into your data warehouse. Every event — a send, open, click, close, rich or in-app message interaction, custom conversion, or control (holdout) — is captured individually and attributed to the specific push that a journey, automation, or one-off campaign triggered.

This is the right source when you need engagement feedback at the message level: which journey-triggered pushes were delivered, opened, and converted, per user and per variant. It is not the aggregate Reports API — it emits one warehouse row per event.

Prerequisites

  • An Airship project with Real-Time Data Streaming (RTDS) enabled. RTDS is a paid add-on — contact Airship to enable it for your project if it is not already active.
  • An RTDS access token (see Authentication).
  • Your project’s app key.
  • Knowledge of your project’s data-residency region (US or EU).
  • A connected Warehouse (target warehouse) with write permissions on the target schema.

Authentication

The Airship loader uses token authentication against the RTDS event stream. Two values are required.

Obtaining an RTDS Access Token

  1. Log in to the Airship dashboard  and select your project.
  2. Open Settings > Project settings > Real-Time Data Streaming.
  3. Under Direct Integration, click Create Access Token.
  4. Copy the token immediately — it is shown once and cannot be retrieved later.
  5. In Zeotap, paste it into the RTDS Access Token field.

Finding your App Key

Your App Key identifies the project. Find it under Settings > Project settings > APIs & Integrations > App keys & secrets. Paste it into the App Key field.

The loader sends these as Authorization: Bearer <access token> and X-UA-Appkey: <app key> on every request.

Configuration

SettingDescriptionDefault
RTDS Access TokenReal-Time Data Streaming access token (Direct Integration)— (required)
App KeyYour Airship project/app key— (required)
Data RegionData-residency region — US (connect.urbanairship.com) or EU (connect.asnapieu.com)US
Initial PositionWhere to start on the first sync, before any offset is saved. EARLIEST backfills the available data window (~last 7 days); LATEST captures only new events from now onEARLIEST
Event TypesWhich event types to capture. Defaults to the engagement/attribution set; narrow or widen as neededEngagement set (below)
Max Poll SecondsSafety cap on how long a single sync reads the stream before stopping and checkpointing300
Max Events Per RunSafety cap on how many events a single sync ingests before stopping and checkpointing1000000

The default Event Types set covers everything with push/journey attribution plus custom conversions: SEND, PUSH_BODY, OPEN, CLOSE, CONTROL, RICH_DELIVERY, RICH_READ, RICH_DELETE, IN_APP_MESSAGE_DISPLAY, IN_APP_MESSAGE_RESOLUTION, IN_APP_MESSAGE_EXPIRATION, WEB_CLICK, WEB_SESSION, CUSTOM.

Available Objects

The loader exposes a single stream. Each event type lands as a row in the same table, discriminated by the type column.

ObjectAPI NameDescriptionDefault Sync Mode
Engagement EventseventsRow-level RTDS events (sends, opens, clicks, closes, rich/in-app, custom, control), each attributed to the push/journey that triggered itIncremental

Key Columns

The events table flattens the event envelope, the device/user identity, and the union of engagement body fields. Notable columns:

ColumnTypeDescription
idstringUnique event ID — de-duplicate on this (delivery is at-least-once)
offsetstringOpaque stream cursor (the incremental high-watermark)
occurreddatetimeWhen the event happened
processeddatetimeWhen Airship ingested the event
typestringEvent type (SEND, OPEN, CLOSE, CUSTOM, …)
device_channelstringAirship channel ID (device)
device_named_user_idstringNamed user ID — your customer identifier
body_push_idstringThe push that produced this event
body_group_idstringThe automation/journey/sequence group (fans out to many pushes)
body_variant_idintegerA/B test variant number
from_automationbooleanDerived — true when the event is attributed to an automation/journey group (body_group_id, or the direct-open triggering_push group)
body_triggering_push_push_idstringDirect-open attribution — the push the user tapped
body_last_delivered_push_idstringInfluenced-open attribution — the most recent push delivered
body_name / body_valuestring / numberCustom event name and value
body_campaignsjsonCampaign categories you assigned
body_rawjsonThe complete event body — nothing is lost

Attributing an event to a journey

Airship does not label events “journey” directly; you infer it from the body:

  • body_group_id present → the send was delivered as part of an automation, sequence, or journey (one group ID fans out to many push_ids). The from_automation column surfaces this as a boolean.
  • body_push_id present with no body_group_id → a one-off push sent at a defined time.
  • body_variant_id present → the push was part of an A/B test.
  • A CONTROL event (type = 'CONTROL') → the device was held out of that push/experiment — filter on the event type (with body_group_id) to build the holdout cohort for uplift measurement.

Sync Modes

  • Incremental (default) — The stream is resumable by offset. Zeotap saves the highest offset it has read and passes it back as resume_offset on the next sync, so each run picks up exactly where the last left off. This is the only supported mode.
  • First run — Uses the Initial Position setting (EARLIEST or LATEST) instead of an offset.

Data Window & High Volume

This loader consumes Airship’s live event stream, which is designed for near-real-time ingestion — capturing engagement events as they happen. Two limits of the stream are worth understanding up front:

  • Resumable window — ~7 days or 100 GB, whichever comes first. Airship retains only a rolling data window; a saved offset (or an EARLIEST start) can reach back at most this far. There is no way to replay older row-level events through the stream.
  • Event-age limit — 90 days. Airship does not process events whose occurrence timestamp is older than 90 days.

Because of this, the loader is best run on a frequent schedule so it never falls behind the window. It does not backfill months of history — that data is not available from the stream. (Aggregate historical reporting is available separately through Airship’s Reports; a one-time row-level historical export is an Airship Support engagement.)

Sizing runs for high volume

The Max Events Per Run and Max Poll Seconds settings are configurable safety caps — a run normally stops earlier when it catches up to now, but these bound a run on a project busy enough that the stream never goes idle. The defaults (1,000,000 events / 300 seconds) comfortably drain a 30–60 minute window at ~10M events/day (~417k/hour).

  • If a single scheduled window exceeds what one run can drain, the loader checkpoints its offset and the next run continues — no data is lost; catch-up simply spreads across runs.
  • The real ceilings on a single run are the job’s execution time limit, its memory budget, and your warehouse’s write throughput.
  • For very high steady-state volume, raise the caps and/or sync more frequently so throughput keeps pace with your event rate. A run that keeps hitting the caps every time is the signal to increase them or shorten the schedule interval.

How It Works

  • Streaming, not paging — RTDS returns an unending stream of newline-delimited JSON, one event per line. The loader reads it line by line, flattens each event, and writes rows in batches — it never buffers the whole stream in memory.
  • Cursor checkpointing — The offset is the incremental cursor. The loader tracks the maximum offset seen and checkpoints it after each batch; Zeotap persists it between runs.
  • Bounding a scheduled run — Because the stream never ends on its own, each sync self-terminates when it has drained to “now” (Airship sends an idle keep-alive / OFFSET_UPDATE), or when it hits the Max Poll Seconds or Max Events Per Run cap. Whatever the stop reason, the latest offset is saved so the next scheduled run resumes cleanly.
  • At-least-once delivery — The stream occasionally repeats an event; duplicates share the same id but have a different offset. The loader de-duplicates on id within a run, but events can still repeat across runs. De-duplicate on id in your models for exactly-once semantics.

Schema Mapping

Airship TypeWarehouse TypeNotes
ISO-8601 timestamp (occurred, processed, *_time)TIMESTAMPParsed and stored as UTC
variant_idBIGINTA/B variant number
value (custom events)DOUBLENumeric custom-event value
alerting, trimmed, from_automationBOOLEAN
identifiers, attributes, campaigns, context, properties, body_rawJSON / VARCHARNested objects stored as JSON
everything elseVARCHARIDs, channels, event type, session

Rate Limits

RTDS is designed for high-volume streaming and does not publish a fixed request quota. The loader honors backoff on throttling (HTTP 429) and 5xx responses. The resumable data window holds roughly the last 7 days (or 100 GB) of events — a saved offset older than that may no longer be resumable, in which case the sync restarts from the Initial Position.

Troubleshooting

IssueSolution
”Real-Time Data Streaming unavailable” / HTTP 402RTDS is a paid add-on — contact Airship to enable it, then create a Direct Integration access token. This status is also returned if you exceed the allowed number of simultaneous connections
”No data for this app key” / HTTP 404Airship has no stream data for the supplied app key — verify the App Key and that the Data Region (US/EU) matches your project
”Authentication failed” / HTTP 401Verify the RTDS access token and app key. The token is shown only once at creation — recreate it if it was lost
HTTP 406 on connectThe API version header was rejected — this is a loader-side issue; contact support
No new rows on a runIf nothing happened in your project since the last sync, there is nothing to ingest. The offset is unchanged and the next run resumes correctly
Duplicate rowsDelivery is at-least-once. De-duplicate on the id column in your models
Backfill returns fewer events than expectedThe resumable window is ~7 days / 100 GB. Older events are outside the stream’s horizon
Some events have no push_id/group_idEvents not originated by an Airship push (e.g. app-defined in-app messages, some custom events) carry no push attribution — this is expected
A run stops before draining the whole backlogIt hit the Max Poll Seconds or Max Events Per Run cap. The offset is checkpointed and the next scheduled run continues — no data is lost. Raise the caps or sync more frequently for very high volumes
Need to load more than ~7 days of historyThe live stream only retains ~7 days / 100 GB and won’t replay older events. Run the loader frequently so it stays within the window; for one-time row-level history beyond that, contact Airship Support

Next Steps

  • Create a model to transform raw Airship events — de-duplicate on id, then join body_group_id to your journey definitions
  • Measure journey engagement by aggregating OPEN / CUSTOM events per body_group_id and body_variant_id
  • Compare CONTROL (holdout) cohorts against exposed cohorts for uplift
  • Sync enriched engagement data back to your activation tools
Last updated on