Creating Apps
An app represents one platform you track users on - your website, your iOS app, or your Android app - and owns the SDK key that platform's build uses. This page walks through creating an app and getting the first events flowing.
Apps are created inside a workspace, and you need settings write permission in that workspace.
1. Create the app
- In the Joryio dashboard, go to Settings → Apps.
- Click Create App.
- Enter an App Name - make it recognizable, e.g. "Production Website" or "iOS - App Store".
- Select the Platform: Web, iOS, or Android. The platform cannot be changed later - create a new app instead. (Shopify, WooCommerce, and Magento apps are created automatically by their integrations, not from this dialog.)
- Click create.
If you ship on several platforms, create one app per platform - see Multi-Platform Tracking. For React Native, create an iOS app and an Android app.
2. Copy the SDK key
The new app appears in the apps table with its generated SDK key, in the format jry_sdk_<platform>_<random>:
jry_sdk_web_4f2a9c...
Use the copy button in the SDK Key column. Treat the key as configuration, not a secret to hardcode: load it from an environment variable, and never commit it to a public repository. If a key leaks, use Regenerate Key on the app row - the old key stops working immediately, so update your deployment first.
3. Wire the SDK
Install and initialize the SDK that matches the app's platform, passing the key you copied:
| Platform | SDK guide | Initialize with |
|---|---|---|
| Web | Web SDK | new JoryioSDK({ sdkKey: 'jry_sdk_web_...' }) |
| iOS | iOS SDK | Joryio.shared.initialize(sdkKey: "jry_sdk_ios_...") |
| Android | Android SDK | Joryio.initialize(context, "jry_sdk_android_...") |
| React Native | React Native SDK | Joryio.initialize(key, apiHost) with the iOS or Android key per Platform.OS |
The key must match the platform - a jry_sdk_web_... key in the iOS SDK will not track that build as an iOS app.
Then identify users and track your first event:
// Web SDK example - the other platforms use the equivalent calls
const joryio = new JoryioSDK({ sdkKey: 'jry_sdk_web_...' });
joryio.identify('user_123');
joryio.track('order_placed', { order_id: 'ORD-001', total: 149.99 });
4. Verify events arrive
- Trigger an event in your app (or just load a page - the SDK tracks
Session Startautomatically). - Open Analytics → Event Explorer in the dashboard and look for the event. SDKs batch events and flush every few seconds, so allow a short delay - or call
flush()to send immediately. - For a per-app check, go back to Settings → Apps and click View Analytics on the app: it shows total events, active users, and the last event timestamp for that SDK key.
If nothing shows up, work through the checklist in Tracking Events - Verifying and debugging.
Ongoing management
From the app's row in Settings → Apps you can also:
- Configure push credentials - APNS for iOS, FCM for Android, or enable web push (VAPID) for web apps.
- Deactivate an app - events sent with a deactivated app's key are rejected; historical events are preserved.
- Regenerate the SDK key - immediate, breaking rotation.
- Enable SDK Authentication - optionally require a customer-signed JWT (in the
X-Joryio-Authheader) on every ingest request for the app, verified against a public key you register. - Delete the app - stops tracking for that key permanently; historical events are preserved.
Securing identity: SDK Authentication (recommended)
Your SDK key is publishable - it ships in your website/app and is, by design, extractable by anyone. On its own it authenticates the app, not the end user: like every client-side analytics SDK, a request carries a client-supplied userId/anonymousId that identifies which contact it is about but does not prove the caller controls that contact.
For most event tracking that is fine. But for sensitive identity operations - changing consent, registering a push destination, setting profile attributes, or merging profiles via identify - it means someone with your SDK key and a known contact id could act on that contact. To close this, enable SDK Authentication:
- Your backend signs a short-lived JWT (RS256/ES256) whose subject is the identified user, and the SDK sends it in
X-Joryio-Auth. Joryio verifies it against the public key you register, so a request is bound to a proven user. This is the standard model for authenticating client-side SDK traffic. - Once enabled, anonymous-only sensitive writes are rejected (an
anonymousIdcan't be cryptographically bound) - callidentify(userId)first. Plain event tracking is unaffected.
For the strictest posture, turn on Strict SDK identity on the app: it requires an SDK-Authentication-verified userId for every sensitive mutation (consent, push registration, identify), rejecting anonymous and un-authenticated attempts outright.
We recommend enabling SDK Authentication for any app that lets end users manage consent or receive push.
Choose a userId that cannot be guessed
SDK Authentication is optional, and it is your call whether to turn it on. Until you do, the userId is the only thing standing between a request and a contact - so which identifier you pick is itself a security decision.
A user can always read their own identifier out of their own traffic. That is unavoidable and harmless. What matters is that knowing one identifier tells an attacker nothing about anybody else's.
Avoid
- Email addresses and phone numbers. Anyone who can name your customer can produce their identifier. Hashing does not help: whoever knows the email can compute the same hash.
- Sequential or auto-increment database ids. One known id gives away every other, by counting.
- Anything already public - values that appear in URLs, page source, order confirmations or support tickets.
Prefer
- An opaque, random, per-user value - a UUIDv4 generated once and stored against your user record.
- Stable for the life of the account. Changing it splits one person into two contacts, which breaks history and consent.
This is defence in depth, not a replacement. A random userId raises the cost of a targeted attack; SDK Authentication removes the whole class. If your app lets end users manage consent or receive push notifications, do both.