Appearance
Core concepts
A few ideas explain the whole product. Once you know them, every page in the dashboard and every field in the API makes sense.
The hierarchy
Organization your team, its plan and billing
└── Project one app, game or website
└── Environment production, staging, development…
└── Deployment one build or source: iOS, Android, web, API server
└── Keys sdl_pub_… and sdl_sec_…, each belongs to one deploymentOrganization
Your team. It holds the members, the plan and the monthly event quota. Everything below it belongs to exactly one organization.
People in it have one of three roles:
| Role | Can |
|---|---|
| Owner | Everything, including billing, members, alerts, prices, public counters and erasing data |
| Member | Read everything, edit dashboards and boards, work on issues, export and manage webhooks |
| Viewer | Read dashboards, logs and events only; never keys or billing. Viewers are free on paid plans and don't use a seat |
Project
One product, such as your Mac app or your website. A project has a name, a logo or emoji, and a time zone: "today" on the dashboard means today in that zone. Times are always stored in UTC.
Environment
A separate data set inside a project, such as production and development. Each environment has its own dashboard, logs, devices, keys, alerts and retention. Data never mixes between environments.
Deployments
The builds or sources that send data into one environment. For example, production might have ios, android, macos and web deployments.
- Every environment starts with one deployment called
default. - Once there are two, the dashboard shows an All tab plus one tab per deployment.
- A deployment has a name and a platform (
ios,android,macos,windows,linux,web,serverorother), used for its icon. An environment holds up to 20. - On the Deployments & keys tab, Add deployment picks a platform and a name; Create key on its card then gives it a key.
- Delete in a deployment's menu removes it and its keys while none of them has stored data. A deployment with data, a webhook source or no sibling stays, and its menu says why.
You never send a deployment name. The key decides it.
Ingest keys
Every request carries an ingest key, and the key alone decides the environment and the deployment. Your payloads never name either.
| Kind | Prefix | Where it goes | Can it read data? |
|---|---|---|---|
| Public | sdl_pub_… | Apps, games and websites. Safe to ship in a binary or a web page | No, write-only |
| Secret | sdl_sec_… | Servers, log shippers, CI | No, write-only |
Both kinds only write. Neither can read your data, so a public key scraped from your website can at worst send junk events. If that happens, revoke it on the Deployments & keys tab and create a new one: other deployments keep working.
One key per build
Give each build or source its own deployment and key. Your iOS and web numbers then get their own tabs, and you can rotate one key without touching the others.
A deployment can hold several keys at once, which is how you rotate: create the new key, ship it, then revoke the old one. A revoked key stops working within about 30 seconds.
Reading data is separate. The dashboard uses your sign-in, and the MCP server uses OAuth or a personal sdl_mcp_… token.
Events and log lines
simpledatalogs does two jobs, and every row is one of two kinds.
Events
An event has a name and counts something that happened:
json
{"event": "screenshot_taken", "device_id": "c0ffee-42", "props": {"type": "area"}}Events become counters, charts over time, breakdowns by property, and unique-device counts.
Log lines
A log line has a message and, usually, a level. It has no event name:
json
{"level": "error", "message": "Upload failed", "props": {"status": 503}}Log lines land on the Logs tab, where you can filter by level, deployment and text, and they also feed the log-level chart. You can send them as JSON or as plain text in almost any common format.
The levels are a closed set: debug, info, notice, warning, error and critical. Common spellings such as WARN or fatal map onto them.
Devices and identity
Send an identity field, and the dashboard counts active devices and gives each device its own page. The fields are device_id, install_id, anonymous_id, user_id and session_id.
Use a random install id or an anonymous id, not a name or an email. If an email does arrive in an identity field, it is stored as a stable pseudonym instead. See Privacy for senders.
Props
props holds everything else worth charting: strings, numbers and booleans. Low-cardinality string props, such as plan or platform, become breakdowns automatically.
Any top-level field the API doesn't know moves under props, so {"event": "signup", "plan": "pro"} and {"event": "signup", "props": {"plan": "pro"}} are stored the same way.
Unparsed
Anything that can't become a row, such as invalid JSON, a binary body or a line that doesn't fit your text template, lands in the environment's Unparsed tab with a reason. It is kept for 7 days. When you change the template, or choose Read again, it is read with the current rules.
Next steps
- Sending data: the endpoint, headers and body shapes.
- Events and log objects: every field and its rules.
- Privacy for senders: what not to send, and what is masked for you.