boltZharp Docs
rocket_launchApp Telemetry

Getting Started

Add an app in the dashboard, install the SDK with the key it gives you, and watch the first event arrive.

Add an app

In the dashboard sidebar, open App Telemetry and click Add app (Add your first app when you have none). It takes four steps: Platform, Name, Install and Verify.

  1. 1
    Platform

    Under What are you instrumenting?, pick the platform: Browser, Flutter, Android or iOS for apps people use; Node.js, Python, Go or PHP for servers and APIs; OpenTelemetry for anything else. One app per codebase — a front end and its API are two apps. Click Continue.

  2. 2
    Name

    Enter an App name such as Checkout web and choose the Environment to fill into the setup code. Under Advanced settings you can set the Service name (by default the name in lower case with dashes, checkout-web) and, for a browser app, Allowed origins. Click Create app.

  3. 3
    Install

    The page shows the setup for your platform with the key, service name and environment already filled in, with a tab per framework where it makes a difference. Follow it, then click I've added it. The steps are the same as on each SDK page.

  4. 4
    Verify

    Zharp waits for the first event. Load a page in your app, or send your service a request; it shows up a few seconds later. Send a test event sends one log line with the app's key, which tells you the key works before the SDK is in. If nothing comes after a minute, the page lists the usual causes.

    Once connected, Get the most out of it ticks off each item as its data arrives: Errors, Traces, Logs, Releases, User context, Linked to a backend and, for browser apps, Session replay.

You can leave halfway: the app is created with its key at the second step, and Finish setup next to its name takes you back. Later, the setup is under the app's settings, Setup instructions.

SDK pages

Each SDK page has the same sections — Install, Initialize, Logs, Errors, Readable stack traces, Tracing, User context, Options and Troubleshooting — so once you know one, you know them all.

PlatformPackageCovers
Browser@zharp/browserReact, Vue, Next.js, Angular, plain JavaScript, script tag
Node.js@zharp/nodeExpress, NestJS, Fastify, Koa, Next.js server
PythonzharpDjango, FastAPI, Flask, scripts and workers
Gogithub.com/zharp-io/zharp-go-libnet/http, Gin, Echo, workers
PHPzharp/zharpLaravel, Symfony, plain PHP
Flutterzharp_flutteriOS and Android from one codebase; Dio with zharp_dio
Androidio.zharp:androidKotlin and Java, OkHttp
iOSZharp (Swift package)Swift, SwiftUI and UIKit, URLSession
OpenTelemetryAny OTel SDK or CollectorEvery other language
info
The SDKs are new

The SDKs are at 0.1 (Android at 1.0.0). They are built on the official OpenTelemetry SDK of each language, so what they send is standard OpenTelemetry — but expect their own options to change as they settle.

lightbulb
Only want logs?

The same SDKs send logs and errors without tracing. See Logs from your code.

Keys

Every app has its own ingest key, zpk_ followed by 32 characters. The setup page fills it in; it is also in the app's settings (the gear next to the time window) with a copy button.

  • It can only send. It reads nothing and changes nothing, so it is safe in a web page or a mobile app, where anyone can find it. On a server, keep it in the environment rather than in the repository.
  • Everything it sends belongs to its app, whatever service.name the data carries.
  • Allowed origins (browser apps, in Advanced settings or the app's settings): only pages on these origins may send with the key, one per line, such as https://shop.example.com. Empty allows any. Ingest answers 403 to any other origin. Servers and mobile apps send no origin, so the list doesn't apply to them.
  • Roll key in the app's settings issues a new key. The old one stops working within a minute, and data stops arriving until every SDK has the new one.

You can also send with a workspace API key that can ingest — create one under Integrations & API → Main API keys with Ingest only ticked. Then each record goes to the app whose service name matches its service.name, and an unknown service name creates a discovered app. That suits a Collector or agent sending for many services at once; for a single app, use its own key.

Environments and releases

environment (production, staging…) is recorded on every event and shown on each error. One app can send from several environments with the same key — the environment you chose when adding it only fills in the setup code.

release is the version of the build. With it, the Overview marks when each release first appeared and shows its error rate, and an issue first seen in the newest release is marked New in <release>. Set it from your build — a version number or the commit SHA:

// The same value everywhere this build runs — a version or a commit SHA
Zharp.init({ key: "zpk_…", service: "checkout-web", environment: "production", release: "web@2.3.0" });

Flutter, Android and iOS default to the app's version and build number, so mobile apps have a release without setting one.

Linking a front end to its API

Add the front end and its API as two apps. Then tell the front-end SDK which hosts are yours with tracingOrigins:

import { Zharp } from "@zharp/browser";

Zharp.init({
  key: "zpk_…",
  service: "checkout-web",
  environment: "production",
  release: "1.0.0",                   // optional: see which release broke
  tracingOrigins: ["api.example.com"], // your API, so traces continue into it
  replay: {
    sampleRate: 0.1,         // record 10% of sessions from start to end
    onErrorSampleRate: 1.0,  // and every session that hits an error
  },
});

Requests to those hosts — and, in the browser, to the page's own origin — carry two W3C headers: traceparent, so the API continues the same trace, and baggage with the session and user. The server SDKs read both, so the API's spans, logs and errors are one trace with the click that caused them and are filed under the same user and session. No other host gets the headers: an unexpected header can make a third-party request fail its CORS check.

A cross-origin API has to allow the two headers, or the browser blocks the request:

# alongside the headers your API already allows
Access-Control-Allow-Headers: content-type, traceparent, baggage

Linked to a backend on the setup checklist ticks once a trace continues from one app into another.

Who the user is

Without it, errors and sessions are anonymous. Tell the SDK who is signed in, and every error, trace, log and session after that carries their ID — and the Users tab lists them with everything they did:

// Once someone signs in — and on every page load while they are signed in
Zharp.setUser({ id: user.id, email: user.email });

// On sign-out: forgets them and starts a new session
Zharp.clearUser();
  • id is required and becomes enduser.id; use whatever identifies a person in your app. email and name are optional.
  • In apps people use (browser, Flutter, Android, iOS), the user is sent to your API in baggage, so a server doesn't need to call setUser. On a server, setUser sets the user for the current request — for when the server knows better, or the request didn't come from a Zharp front end.
  • clearUser() on sign-out forgets the user and, on clients, starts a new session.

What else is sent

The client SDKs add the session ID, the browser or device model, and the operating system and its version. Mobile SDKs add a random install ID they create themselves — not an advertising or vendor ID, and gone when the app is uninstalled. Anything else is only what you add with setTag or as attributes on a log or error.