> ## Documentation Index
> Fetch the complete documentation index at: https://docs.tryhelium.com/llms.txt
> Use this file to discover all available pages before exploring further.

# Set Up Revenue Tracking

> Set up webhooks to track your app's revenue and subscription events. This is important if you want Helium to display subscription, revenue, and other metrics!

Go to [Integrations > Revenue Tracking](https://app.tryhelium.com/integrations/revenue) to configure webhooks.

<img src="https://mintcdn.com/helium/vjbIVTFp_dv4L6zW/images/rev-reporting.jpg?fit=max&auto=format&n=vjbIVTFp_dv4L6zW&q=85&s=5a727d069f4d286dc69bef830718bddb" alt="Rev Reporting" width="1600" height="777" data-path="images/rev-reporting.jpg" />

## Configure iOS

Choose ONE of the following 3 options:

### 1) App Store Server Notifications

<Tip>
  This option is recommended if you are using StoreKit to handle your purchases.
</Tip>

Send purchase events direct from Apple to Helium.

### 2) RevenueCat Webhooks

<Tip>
  This option is recommended if you are using RevenueCat to handle your purchases.
</Tip>

Use RevenueCat webhooks to send revenue events to Helium. Follow the instructions shown under **RevenueCat Webhooks**.

### 3) Forward App Store Server Notifications

<Tip>
  This option is recommended if you are using StoreKit to handle your purchases but want to consume App Store Server Notifications on your own server and forward those events to Helium.
</Tip>

Grab the **Webhook URL** from the **App Store Server Notifications** section and use that value in your forwarding code.

Wherever you consume webhook events for App Store Server Notifications, you'll want to add a snippet of code that forwards the exact, unmodified ASSN payload to Helium.

Here is some example forwarding code. Reach out to Helium support if you have any questions.

<CodeGroup>
  ```javascript Node/Express theme={null}
  const express = require('express');
  const axios = require('axios');
  const app = express();

  app.use(express.json());

  app.post('/assn-webhook', async (req, res) => {
    try {
      const response = await axios.post(
        'your-helium-webhook-url-here',
        req.body,
        {
          headers: { 'Content-Type': 'application/json' },
          timeout: 5000
        }
      );

      console.log('Successfully forwarded webhook');
      res.status(200).json({ success: true });
    } catch (error) {
      console.error('Failed to forward webhook:', error.message);
      res.status(500).json({ error: 'Failed to forward webhook' });
    }
  });
  ```

  ```javascript Next.js Pages Router theme={null}
  export default async function handler(req, res) {
    if (req.method !== 'POST') {
      return res.status(405).json({ error: 'Method not allowed' });
    }

    try {
      const response = await fetch(
        'your-helium-webhook-url-here',
        {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify(req.body),
          signal: AbortSignal.timeout(5000)
        }
      );

      if (response.ok) {
        console.log('Successfully forwarded webhook');
        return res.status(200).json({ success: true });
      } else {
        throw new Error(`HTTP ${response.status}`);
      }
    } catch (error) {
      console.error('Failed to forward webhook:', error);
      return res.status(500).json({ error: 'Failed to forward webhook' });
    }
  }
  ```

  ```javascript Next.js App Router theme={null}
  import { NextResponse } from 'next/server';

  export async function POST(request) {
    try {
      const body = await request.json();

      const response = await fetch(
        'your-helium-webhook-url-here',
        {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify(body),
          signal: AbortSignal.timeout(5000)
        }
      );

      if (response.ok) {
        console.log('Successfully forwarded webhook');
        return NextResponse.json({ success: true });
      } else {
        throw new Error(`HTTP ${response.status}`);
      }
    } catch (error) {
      console.error('Failed to forward webhook:', error);
      return NextResponse.json(
        { error: 'Failed to forward webhook' },
        { status: 500 }
      );
    }
  }
  ```

  ```python Python w/ Flask theme={null}
  @app.route('/webhook', methods=['POST'])
  def forward_webhook():
      try:
          response = requests.post(
              'your-helium-webhook-url-here',
              json=request.json,
              headers={'Content-Type': 'application/json'},
              timeout=5
          )
          response.raise_for_status()

          print('Successfully forwarded webhook')
          return jsonify({'success': True}), 200

      except requests.exceptions.RequestException as e:
          print(f'Failed to forward webhook: {e}')
          return jsonify({'error': 'Failed to forward webhook'}), 500
  ```

  ```python Python w/ FastAPI theme={null}
  @app.post('/webhook')
  async def forward_webhook(request: Request):
      try:
          body = await request.json()

          async with httpx.AsyncClient(timeout=5.0) as client:
              response = await client.post(
                  'your-helium-webhook-url-here',
                  json=body,
                  headers={'Content-Type': 'application/json'}
              )
              response.raise_for_status()

          print('Successfully forwarded webhook')
          return {'success': True}

      except (httpx.RequestError, httpx.HTTPStatusError) as e:
          print(f'Failed to forward webhook: {e}')
          raise HTTPException(
              status_code=500,
              detail='Failed to forward webhook'
          )
  ```
</CodeGroup>

<Tip>
  You may want to extract the pk value from the Webhook URL as an environment variable to avoid storing in version control.
</Tip>

## Configure Android

Choose ONE of the following 2 options:

### 1) Google Play RTDN

<Tip>
  This option is recommended if you are NOT using RevenueCat to handle your purchases.
</Tip>

Utilize Google Play Real-Time Developer Notifications to send revenue events to Helium.

### 2) RevenueCat Webhooks

<Tip>
  This option is recommended if you are using RevenueCat to handle your purchases.
</Tip>

Use RevenueCat webhooks to send revenue events to Helium. Follow the instructions shown under **RevenueCat Webhooks**.
