OwlMetry

Events

Understand how OwlMetry captures, stores, and queries events with log levels, sessions, and timestamps.

Events are the core data unit in OwlMetry. Every interaction your app records -- a screen view, a button tap, a warning, an error -- is captured as an event and sent to the server for storage and analysis.

Add event logging with your coding agent
Instrument this project with OwlMetry event logging.
Run `owlmetry skills` to find the SDK skill file for this platform.

- Add Owl.info/warn/error calls at key points: caught exceptions,
  user actions, state transitions, and failure paths.
- Add .owlScreen() to every distinct screen for automatic screen
  view tracking.
- Don't log inside loops or high-frequency callbacks — each call
  sends a network event.

Event Structure

Each event contains the following fields:

FieldTypeRequiredDescription
messagestringYesWhat happened -- a human-readable description of the event
levelstringYesLog level: info, debug, warn, or error
session_idstring (UUID)YesGroups events from a single app session
client_event_idstring (UUID)NoClient-generated ID used for deduplication
user_idstringNoUser identifier (anonymous or real)
source_modulestringNoModule or component that generated the event
screen_namestringNoCurrent screen or page name
custom_attributesobjectNoArbitrary string key-value pairs (200 char value limit)
environmentstringNoRuntime environment (ios, ipados, macos, android, web, backend)
os_versionstringNoOperating system version
app_versionstringNoApp version string
build_numberstringNoApp build number
device_modelstringNoDevice hardware model
localestringNoUser locale (e.g., en_US)
is_devbooleanNoWhether the event came from a development build
experimentsobjectNoActive A/B experiment variant assignments
timestampstring (ISO 8601)NoWhen the event occurred (server uses receipt time if omitted)

Events are sent to the server in batches via the ingest endpoint. The SDKs handle batching automatically.

Log Levels

Every event has a log level that indicates its severity:

LevelPurpose
infoNormal activity -- screen views, user actions, lifecycle events
debugDiagnostic information useful during development
warnSomething unexpected happened but the app continued normally
errorSomething failed -- a network request, a parse operation, etc.

The dashboard and CLI support filtering events by level to help you focus on what matters.

Sessions

A session_id is a UUID generated fresh every time an SDK calls configure(). This typically happens once per app launch, so a session corresponds to a single run of your app from open to close.

All events emitted during that session share the same session_id, which allows you to:

  • Reconstruct a user's journey through a single app session
  • Filter the event timeline to a specific session
  • Count unique sessions over a time period

The SDKs generate the session ID automatically. You do not need to manage it yourself.

Timestamp Validation

The server validates event timestamps on ingestion:

  • Future limit: Events with timestamps more than 5 minutes in the future are rejected.
  • Past limit: Events with timestamps more than 30 days in the past are rejected.
  • Invalid format: Events with unparseable timestamps are rejected.

If a timestamp is omitted, the server uses the time the event was received.

Deduplication

If an event includes a client_event_id, the server checks for duplicates within a 48-hour window. If an event with the same client_event_id and app_id was already ingested, the duplicate is silently dropped.

This makes it safe for SDKs to retry failed ingestion requests without creating duplicate data. The 48-hour window is bounded so Postgres can skip older partitions during the lookup.

Custom Attributes

Events can carry arbitrary metadata as custom_attributes -- a flat object of string keys and string values. Each value is limited to 200 characters.

{
  "custom_attributes": {
    "plan": "pro",
    "feature_flag": "new-checkout",
    "item_count": "3"
  }
}

The SDKs also auto-capture certain fields as custom attributes. For example, the Swift SDK records _connection (wifi, cellular, ethernet, offline) via its network monitor.

Auto-Captured Fields

The SDKs automatically populate device and app metadata on every event without any additional configuration:

  • device_model -- hardware model (e.g., "iPhone15,2")
  • os_version -- operating system version (e.g., "17.4.1")
  • app_version -- the app's version string from its bundle or package
  • build_number -- the app's build number
  • locale -- the device locale (e.g., "en_US")
  • environment -- the runtime platform (ios, ipados, macos, android, web, backend)
  • is_dev -- whether this is a development build (see Data Mode)

For SDK-specific details, see the Swift SDK events guide or the Node SDK events guide.

Partitioned Storage

Events are stored in a PostgreSQL table partitioned by month on the timestamp column. Partitions for the current month and the next two months are created automatically on server startup and during migrations.

Monthly partitioning allows Postgres to scan only the relevant partitions when querying a date range, keeping event queries fast as your data grows. The events table has no primary key or foreign keys due to PostgreSQL partition constraints -- data integrity is enforced at the application level.

Querying Events

Events can be queried through the dashboard, the CLI, or the API. Common filters include:

  • Team, project, or app -- scope events to a specific context
  • Log level -- filter by severity
  • User ID or session ID -- trace a specific user or session
  • Environment -- filter by platform (ios, android, web, etc.)
  • Screen name -- find events from a specific screen
  • Date range -- query a time window
  • Data mode -- filter by production, development, or all (see Data Mode)

Results are paginated with cursor-based pagination.

Ready to get started?

Install the CLI and let your agent handle the rest.