# Track Metrics
The SideKit SDK provides multiple ways to send analytics signals. This data powers your dashboard charts and allows you to build targeted version gates based on user behavior.
Make sure you've configured the SDK with your API key before sending any signals to ensure they are tracked correctly.
## Add Your Custom Signal in the Dashboard
Navigate to the `Settings` page for your app and add your signal in the `Custom Signals` section. Here `purchases` is a custom signal we've chosen to track for this app. This whitelists the signal name and SideKit will accept data for this signal.
## Sending Signals
:::ios
You can track events in your app using three primary methods, depending on how much detail you need.
:::
### 1. Simple Key
The simplest way to send a signal is with just a key string. This is perfect for binary events (like "session\_start").
:::ios
```swift
SideKit.shared.sendSignal("user_login")
```
:::
### 2. Key-Value Pairs
Send a signal with both a key and a value. SideKit automatically generates pie charts in your dashboard for the distribution of these values.
:::ios
```swift
SideKit.shared.sendSignal(key: "purchase_amount", value: "99.99")
```
:::
:::ios
### 3. Signal Objects
For more complex scenarios, you can use the `SideKit.Signal` struct. This is especially useful when building arrays of signals.
```swift
SideKit.shared.sendSignal(
SideKit.Signal(name: "button_click", value: "checkout")
)
```
:::
***
## Bulk Tracking
If you have multiple events that happen simultaneously, you can batch them into a single call:
:::ios
```swift
let signals = [
SideKit.Signal(name: "page_view", value: "home"),
SideKit.Signal(name: "interaction", value: "header_clicked")
]
SideKit.shared.sendSignal(signals)
```
:::
## Best Practices
Batch when possible
: If sending multiple signals in a loop, batch them into an array to reduce network requests.
Use descriptive keys
: Choose clear, consistent names (e.g.,
onboarding_step_1
) to keep your dashboard organized.
Analytics state
: SideKit respects the user's analytics preference. If analytics is disabled, signals will be silently ignored.
# Add an App
Select
Add new app
from the app switcher in the top left of the dashboard.
Enter your app's name as well as an App Store and/or Play Store URL if your app is currently live.
If your app is already live on the App Store, SideKit will automatically pull your app icon from your store URL. If it's not live yet, don't worry—you can always update the icon URL later.
## What's a Signal?
A signal is an analytics metric that you'd like to track with SideKit. Any time the event you'd like to track takes place in your app you can [record it with the SideKit SDK](../analytics/track-a-signal).
### Default Signals
SideKit automatically records three essential signals out-of-the-box so you can start seeing data immediately:
We keep default signals to a minimum, you get to decide what you want to track.
# Configure SideKit
## Add SideKit to your Project
:::ios
To add the SideKit iOS SDK to your Xcode project, follow these steps:
In Xcode, go to
File
\>
Add Package Dependencies...
In the search bar, enter the GitHub URL:
```
https://github.com/appsidekit/ios-sdk
```
Select the
ios-sdk
package from the results
Configure the dependency rule:
-
Set
Dependency Rule
to "Up to Next Major Version"
-
This will use versions
1.0.0
up to (but not including)
2.0.0
Click
Add Package
to complete the installation.
Ensure
SideKit
appears in your project settings under
General
\>
Frameworks, Libraries, and Embedded Content
.
:::
## Configure SideKit in your app
:::ios
In your `ContentView`, add the configuration in a `.task` modifier with your [API key](/ios/helpers/find-api-key):
```swift
.task {
await SideKit.shared.configure(
apiKey: "YOUR-API-KEY",
verbose: true // Optional: enables detailed logs
)
}
```
In your `AppDelegate` or `SceneDelegate`, call configure in `application(_:didFinishLaunchingWithOptions:)` or `scene(_:willConnectTo:options:)`:
```swift
Task {
await SideKit.shared.configure(
apiKey: "YOUR-API-KEY",
verbose: true // Optional: enables detailed logs
)
}
```
:::
Set verbose = true during development to see all SideKit logs in your console.
This is helpful for verifying that your signals are being tracked successfully.
The SideKit SDK will now be available in your app, and you can start sending signals!
# Find Your API Key
Your API key is a unique identifier used to authenticate your app's requests to SideKit.
## Locating your API Key
Navigate to your app in the SideKit dashboard.
Select
Settings
from the sidebar navigation menu.
Scroll down to the
Danger Zone
section to find your key.
## Rotating Your API Key
If your API key is compromised, you can generate a new one by clicking the **Rotate** button.
Rotating your API key is irreversible. Once rotated:
-
Older app versions using the old key will stop sending signals.
-
Version gates will no longer be enforced on those versions.
-
You must release an update with the new key immediately.
# Find Your Bundle ID
:::ios
A **Bundle ID** (Bundle Identifier) is a unique identifier that represents your app on the App Store. They typically follow a reverse-DNS format, such as `com.yourcompany.appname`. Read more [here](https://developer.apple.com/documentation/appstoreconnectapi/bundle-ids).
## Locating the Bundle ID in Xcode
You can find your Bundle ID in your project settings.
Open your project in Xcode and select the project file at the top of the
Project Navigator
.
Select your app target under the
Targets
list.
Go to the
General
tab and look for the
Identity
section.
:::
Bundle IDs are case-sensitive! Double-check for any accidental capital letters or spaces.
# Track Metrics
The SideKit SDK provides multiple ways to send analytics signals. This data powers your dashboard charts and allows you to build targeted version gates based on user behavior.
Make sure you've configured the SDK with your API key before sending any signals to ensure they are tracked correctly.
## Add Your Custom Signal in the Dashboard
Navigate to the `Settings` page for your app and add your signal in the `Custom Signals` section. Here `purchases` is a custom signal we've chosen to track for this app. This whitelists the signal name and SideKit will accept data for this signal.
## Sending Signals
:::react-native
You can track events in your app using two primary methods, depending on how much detail you need.
:::
### 1. Simple Key
The simplest way to send a signal is with just a key string. This is perfect for binary events (like "session\_start").
:::react-native
```ts
const { sendSignal } = useSideKit();
sendSignal("user_login")
```
:::
### 2. Key-Value Pairs
Send a signal with both a key and a value. SideKit automatically generates pie charts in your dashboard for the distribution of these values.
:::react-native
```ts
sendSignal("purchase_amount", "99.99")
```
:::
***
## Bulk Tracking
If you have multiple events that happen simultaneously, you can batch them into a single call:
:::react-native
```ts
const { sendSignals } = useSideKit();
sendSignals([
{ key: "page_view", value: "home" },
{ key: "interaction", value: "header_clicked" }
])
```
:::
## Best Practices
Batch when possible
: If sending multiple signals in a loop, batch them into an array to reduce network requests.
Use descriptive keys
: Choose clear, consistent names (e.g.,
onboarding_step_1
) to keep your dashboard organized.
Analytics state
: SideKit respects the user's analytics preference. If analytics is disabled, signals will be silently ignored.
# Add an App
Select
Add new app
from the app switcher in the top left of the dashboard.
Enter your app's name as well as an App Store and/or Play Store URL if your app is currently live.
If your app is already live on the App Store, SideKit will automatically pull your app icon from your store URL. If it's not live yet, don't worry—you can always update the icon URL later.
## What's a Signal?
A signal is an analytics metric that you'd like to track with SideKit. Any time the event you'd like to track takes place in your app you can [record it with the SideKit SDK](../analytics/track-a-signal).
### Default Signals
SideKit automatically records three essential signals out-of-the-box so you can start seeing data immediately:
We keep default signals to a minimum, you get to decide what you want to track.
# Configure SideKit
## Add SideKit to your Project
:::react-native
To add the SideKit React Native SDK to your project, just install the NPM package:
```sh
npm install @sidekit/react-native @react-native-async-storage/async-storage
# or
yarn add @sidekit/react-native @react-native-async-storage/async-storage
```
:::
## Configure SideKit in your app
:::react-native
To initialize SideKit, wrap your app's contents with `SideKitProvider`:
```ts
import { SideKitProvider } from '@sidekit/react-native';
function App() {
return (
);
}
```
:::
Set verbose = true during development to see all SideKit logs in your console.
This is helpful for verifying that your signals are being tracked successfully.
The SideKit SDK will now be available in your app, and you can start sending signals!
# Find Your API Key
Your API key is a unique identifier used to authenticate your app's requests to SideKit.
## Locating your API Key
Navigate to your app in the SideKit dashboard.
Select
Settings
from the sidebar navigation menu.
Scroll down to the
Danger Zone
section to find your key.
## Rotating Your API Key
If your API key is compromised, you can generate a new one by clicking the **Rotate** button.
Rotating your API key is irreversible. Once rotated:
-
Older app versions using the old key will stop sending signals.
-
Version gates will no longer be enforced on those versions.
-
You must release an update with the new key immediately.
# Find Your Bundle ID
:::react-native
A **Bundle ID** (Bundle Identifier) is a unique identifier that represents your app on the App Store/Play Store. They typically follow a reverse-DNS format, such as `com.yourcompany.appname`. Read more [here](https://developer.apple.com/documentation/appstoreconnectapi/bundle-ids).
## Locating the Bundle ID in your Expo Project
You can find your Bundle IDs for both iOS and Android in your app's `app.json` file:
```json
{
"expo": {
...
"ios": {
"bundleIdentifier": "com.sidekit.example"
},
"android": {
"package": "com.sidekit.example"
},
...
}
}
```
:::
Bundle IDs are case-sensitive! Double-check for any accidental capital letters or spaces.
# Block an App Version
## In the Dashboard
Navigate to `Versions` in the Dashboard under your app. SideKit will use analytics data to automatically infer the most popular app versions from the last 7 days. Tap configure to add an app version to SideKit's tracking.
On an existing version you can set the status as forced or dismissible to block the version. Forced gates require users to update their app to proceed whereas dismissible gates can be skipped.
## In Your App
### Automatic ✨
Zero Code Required
SideKit automatically presents a beautiful version gate when users need to update.
No setup, no code, no maintenance required.
Latest version pulled from App Store automatically
"What's New" text synced from your App Store submission
Works out-of-the-box with zero configuration
### Custom View for Blocked App Versions
For custom version gates, see [Showing Custom Version Gates](./showing-custom-version-gates).
# Set a Minimum Version
## In the Dashboard
Navigate to `Versions` in the Dashboard under your app, set `MIN` from the dropdown to set an app version as a floor. Users on that app version or above will be able to access the app and any users below it will be shown a forced version gate which will require them to update their app to proceed.
## In Your App
### Automatic ✨
Zero Code Required
SideKit automatically presents a beautiful version gate when users need to update.
No setup, no code, no maintenance required.
Latest version pulled from App Store automatically
"What's New" text synced from your App Store submission
Works out-of-the-box with zero configuration
Version gates triggered by minimum version requirements are never dismissible.
Users must update to continue using the app. The "Skip for now" button only appears in dismissible version gates.
### Custom View for Blocked App Versions
For custom version gates, see [Showing Custom Version Gates](./showing-custom-version-gates).
# Showing Custom Version Gates
## Setup
:::react-native
To use custom version gates, configure SideKit with `presentationMode: "manual"`:
```ts
import { SideKitProvider } from '@sidekit/react-native';
function App() {
return (
);
}
```
:::
When using manual presentation mode, you're responsible for displaying the version gate UI.
SideKit will still fetch and manage version requirements, but won't automatically show the update screen.
## GateInformation Struct
Use the `GateInformation` struct to access version gate data and build your custom UI:
:::react-native
```ts
class GateInformation {
gateType: VersionGateType;
lastGateUpdate: string;
latestVersion: string | null;
whatsNew: string | null;
storeUrl: string | null;
}
```
:::
:::react-native
:::
## Gate Types
The `VersionGateType` enum defines version gate behavior:
:::react-native
```ts
enum VersionGateType {
Live = -1,
Forced = 0,
Dismissible = 1,
}
```
:::
### Understanding Gate Types
Live
The user's app version is not blocked by a version gate. You should not show an update screen in this case.
Forced
User must update to continue. The gate cannot be dismissed. Used for critical updates or minimum version enforcement.
Dismissible
User can dismiss the gate and continue using the app. Your custom view should include a close/skip button.
If the gate type is dismissible, your custom view must include UI to close or skip the update.
Failing to do so will trap users in the update screen.
## Displaying Your Custom Gate
:::react-native
```ts
const { showUpdateScreen, gateInformation } = useSideKit();
{showUpdateScreen && gateInformation && (
{/* Show your custom update UI */}
)}
```
:::
:::react-native
Access gateInformation to get the current gate data, including version requirements,
release notes, and App Store/Play Store URL.
:::
# Block an App Version
## In the Dashboard
Navigate to `Versions` in the Dashboard under your app. SideKit will use analytics data to automatically infer the most popular app versions from the last 7 days. Tap configure to add an app version to SideKit's tracking.
On an existing version you can set the status as forced or dismissible to block the version. Forced gates require users to update their app to proceed whereas dismissible gates can be skipped.
## In Your App
### Automatic ✨
Zero Code Required
SideKit automatically presents a beautiful version gate when users need to update.
No setup, no code, no maintenance required.
Latest version pulled from App Store automatically
"What's New" text synced from your App Store submission
Works out-of-the-box with zero configuration
### Custom View for Blocked App Versions
For custom version gates, see [Showing Custom Version Gates](./showing-custom-version-gates).
# Set a Minimum Version
## In the Dashboard
Navigate to `Versions` in the Dashboard under your app, set `MIN` from the dropdown to set an app version as a floor. Users on that app version or above will be able to access the app and any users below it will be shown a forced version gate which will require them to update their app to proceed.
## In Your App
### Automatic ✨
Zero Code Required
SideKit automatically presents a beautiful version gate when users need to update.
No setup, no code, no maintenance required.
Latest version pulled from App Store automatically
"What's New" text synced from your App Store submission
Works out-of-the-box with zero configuration
Version gates triggered by minimum version requirements are never dismissible.
Users must update to continue using the app. The "Skip for now" button only appears in dismissible version gates.
### Custom View for Blocked App Versions
For custom version gates, see [Showing Custom Version Gates](./showing-custom-version-gates).
# Showing Custom Version Gates
## Setup
:::ios
To use custom version gates, configure SideKit with `presentationMode: .manual`:
```swift
SideKit.shared.configure(apiKey: "YOUR-API-KEY", presentationMode: .manual)
```
:::
When using manual presentation mode, you're responsible for displaying the version gate UI.
SideKit will still fetch and manage version requirements, but won't automatically show the update screen.
## GateInformation Struct
Use the `GateInformation` struct to access version gate data and build your custom UI:
:::ios
```swift
struct GateInformation {
let gateType: VersionGateType
let lastGateUpdate: String
let latestVersion: String?
let whatsNew: String?
let storeURL: String?
}
```
:::
:::ios
:::
## Gate Types
The `VersionGateType` enum defines version gate behavior:
:::ios
```swift
enum VersionGateType: Int, Codable {
case live = -1
case forced = 0
case dismissible = 1
}
```
:::
### Understanding Gate Types
Live
The user's app version is not blocked by a version gate. You should not show an update screen in this case.
Forced
User must update to continue. The gate cannot be dismissed. Used for critical updates or minimum version enforcement.
Dismissible
User can dismiss the gate and continue using the app. Your custom view should include a close/skip button.
If the gate type is dismissible, your custom view must include UI to close or skip the update.
Failing to do so will trap users in the update screen.
## Displaying Your Custom Gate
:::ios
Bind your custom gate view to `SideKit.shared.showUpdateScreen` to control when it appears:
```swift
struct ContentView: View {
var body: some View {
YourAppContent()
.fullScreenCover(isPresented: SideKit.shared.$showUpdateScreen) {
if let gateInfo = SideKit.shared.gateInformation {
CustomVersionGateView(gateInfo: gateInfo)
}
}
}
}
```
```swift
class ViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
// Observe showUpdateScreen changes
SideKit.shared.$showUpdateScreen
.sink { [weak self] shouldShow in
if shouldShow, let gateInfo = SideKit.shared.gateInformation {
self?.presentCustomGate(gateInfo)
}
}
.store(in: &cancellables)
}
func presentCustomGate(_ gateInfo: GateInformation) {
let gateVC = CustomVersionGateViewController(gateInfo: gateInfo)
gateVC.modalPresentationStyle = .fullScreen
present(gateVC, animated: true)
}
}
```
:::
:::ios
Access SideKit.shared.gateInformation to get the current gate data, including version requirements,
release notes, and App Store URL. This data is automatically synced from your App Store listing.
:::