# Ingestion Tokens

> Create and manage tokens for sending telemetry data to Last9, including RUM and Prometheus metrics.

Source: https://last9.io/docs/ingestion-tokens/

![Control Plane — Ingestion Tokens](../../../../../assets/content/docs/control-plane/ingestion/ingestion-tokens/control-plane-ingestion-tokens.png)

[Ingestion Tokens](https://app.last9.io/control-plane/ingestion-tokens) authenticate your applications and services when sending telemetry data to Last9. These tokens control what data can be sent and from which origins, ensuring secure data collection.

:::note[Access Requirements]
Only **Admins** can create and delete ingestion tokens. Editors and Viewers can view existing tokens but cannot modify them. See [Users](/docs/users/#api-token-permissions) for the complete permission matrix.
:::

## Creating Ingestion Tokens

![Control Plane — New Ingestion Tokens](../../../../../assets/content/docs/control-plane/ingestion/ingestion-tokens/control-plane-ingestion-tokens-create.png)

1. **Select Token Type**:

   - **Client**: For client-based data collection (eg: RUM)
   - **Prometheus Remote-Write**: For server-side Prometheus-compatible metrics

2. **Client Type** (if Client selected):

   - **Web Browser**: browser RUM — allowlist `https://` origins
   - **Android** / **iOS**: native mobile RUM — allowlist `android://<package>` or `ios://<bundle-id>`
   - **React Native (Android)** / **React Native (iOS)**: React Native RUM — same `android://` / `ios://` origins; create **one token per OS**
   - **Flutter (Android)** / **Flutter (iOS)**: Flutter RUM — same `android://` / `ios://` origins; create **one token per OS**

   All options create the same backend token type (`client_monitoring`). The platform choice only guides the origin format. See [Android](/docs/real-user-monitoring/android/), [iOS](/docs/real-user-monitoring/ios/), [React Native](/docs/real-user-monitoring/react-native/), and [Flutter](/docs/real-user-monitoring/flutter/) RUM docs for platform-specific setup.

3. **Set Origins** (for Client tokens):

   - For web apps, add the domains from which your application will send data — example: `https://www.example.com`
   - For mobile apps, use `android://<package-name>` or `ios://<bundle-id>` instead of a domain — example: `android://com.acme.myapp`
   - For [React Native](/docs/real-user-monitoring/react-native/) and [Flutter](/docs/real-user-monitoring/flutter/) apps, create **separate Client tokens** for Android and iOS (one origin per token) rather than combining both origins on one token
   - Multiple origins can be added to a single token for multi-domain web apps or other cases where one credential should cover several origins
   - **Wildcard subdomains are supported for web origins** using `*.` prefix (e.g., `https://*.example.com`) — not applicable to `android://`/`ios://` origins, which must match exactly

   :::caution
   Data sent from origins not listed here will be rejected.
   :::

   ```
   ✅ Correct Origins:
   https://app.example.com
   https://www.example.com
   http://localhost:3000
   https://*.example.com          (matches any single subdomain)
   https://*.apps.example.com     (matches subdomains of apps.example.com)
   https://app.*.example.com      (matches app.{any}.example.com)
   android://com.acme.myapp       (exact package name, no wildcards)
   ios://com.acme.myapp           (exact bundle ID, no wildcards)

   ❌ Incorrect Origins:
   example.com                    (missing protocol)
   app.example.com                (missing protocol)
   https://example.*              (TLD must be explicit, e.g., .com, .io)
   android://*                    (mobile origins must be an exact package name/bundle ID)
   ```

   ### Wildcard Origins

   Wildcard origins allow you to match multiple subdomains with a single entry. This is useful when:

   - Your application serves multiple customer subdomains (e.g., `customer1.example.com`, `customer2.example.com`)
   - You have dynamic environments that create subdomains on the fly
   - You want to simplify token management across many subdomains

   **Wildcard Rules:**

   | Pattern                      | Matches                                                           | Does Not Match                                       |
   | ---------------------------- | ----------------------------------------------------------------- | ---------------------------------------------------- |
   | `https://*.example.com`      | `https://app.example.com`, `https://www.example.com`              | `https://example.com`, `https://sub.app.example.com` |
   | `https://*.apps.example.com` | `https://prod.apps.example.com`, `https://dev.apps.example.com`   | `https://apps.example.com`                           |
   | `https://app.*.example.com`  | `https://app.staging.example.com`, `https://app.prod.example.com` | `https://app.example.com`                            |

   :::note[Single Level Matching]
   Each `*` matches exactly one subdomain level (alphanumeric characters and hyphens only, no dots). For example, `https://*.example.com` matches `app.example.com` but not `sub.app.example.com`.
   :::

4. **Name Your Token**:

   - Use a descriptive name to identify the token's purpose
   - Example: "Production RUM Token" or "Staging Web Monitoring"

5. Click **CREATE TOKEN** to generate your token

---

## Client Token Security

### Is the Client Token Safe to Expose?

**Yes.** Client tokens are specifically designed to be visible in your frontend code and are safe to include in your application bundle.

#### Why Client Tokens Are Safe

- **Write-Only Permissions**: Client tokens can only send telemetry data to Last9. They cannot read, query, or access any data from your account.
- **CORS-Restricted**: Tokens are restricted to the origins (domains) you configure above, preventing unauthorized websites from using your token.
- **No Account Access**: Client tokens cannot access your Last9 account settings, billing information, or any other sensitive data.
- **Designed for Public Use**: This security model is standard across the industry for frontend monitoring.

#### Why Not Use API Keys?

API keys have full read/write access to your entire Last9 account and should **never** be exposed in frontend code. Client tokens exist specifically to provide a safe way to send telemetry from browsers.

### Security Best Practices

While client tokens are safe to expose, follow these practices to minimize abuse:

1. **Rotate Tokens Periodically**: Rotate your client tokens every 90 days as a preventive measure.

2. **Restrict CORS Origins**: Configure allowed origins (as shown above) to only accept data from your domains.

3. **Use Different Tokens Per Environment**: Use separate tokens for development, staging, and production.

4. **Monitor Usage**: Regularly review your usage dashboard to detect unusual patterns or potential abuse.

### Handling CI/CD Security Scanners

Your CI/CD pipeline security scanners may flag client tokens as secrets. This is a false positive. To resolve:

#### GitGuardian / GitHub Secret Scanning

Add an exception for client tokens:

```yaml
# .gitguardian.yml
paths-ignore:
  - "**/*.html"
  - "**/rum-config.js"

allow-patterns:
  - "clientToken.*"
  - "L9RUM\\.init"
```

#### Inline Comment Exception

Add security scanner directives:

```javascript
// gitguardian:ignore - Public client token with write-only permissions
// nosemgrep: generic.secrets.security.detected-generic-secret
const CLIENT_TOKEN = "your-token-here";
```

---

## Troubleshooting

Please get in touch with us on [Discord](https://discord.com/invite/Q3p2EEucx9) or [Email](mailto:support@last9.io) if you have any questions.
