Swetrix
Analytics Dashboard

Revenue Tracking

Swetrix can track your revenue alongside your analytics data and surface it in the same dashboard you already use. There are three ways to feed transactions in:

  • Stripe — connect a restricted, read-only API key. Sales, subscriptions, and refunds sync automatically every 30 minutes.
  • Paddle — connect a read-only API key. Sales, subscriptions, and refunds (adjustments) sync automatically every 30 minutes.
  • API — POST transactions to Swetrix from your own backend. Use this when you sell through a platform that isn't Stripe or Paddle (Shopify, JTL Shop, Lemon Squeezy, in-app purchases, custom checkouts, etc.) or when you want full control over which events count as revenue.

Once connected, revenue appears as a metric in your Traffic Analytics chart, broken down by the same time periods, comparisons, and filters you already use.

How it works

Connect a source Open Project Settings > Revenue and pick Stripe, Paddle, or the API.

Choose the display currency Swetrix should report in (USD, EUR, or GBP).

Send or sync transactions Stripe and Paddle are pulled automatically every 30 minutes via

read-only API access. With the API option you POST each transaction as it happens.

See it in your dashboard Net revenue shows up as solid bars on the Traffic chart, with

refunds stacked on top. You also get totals, AOV, MRR, and a transactions table.

Supported sources

SourceConnection methodTransaction typesSync model
StripeRestricted API key (read-only)Sales, subscriptions, refundsPulled every 30 min
PaddleAPI key (read-only)Sales, subscriptions, refunds (adjustments)Pulled every 30 min
API (any platform)POST /log/revenue + X-Api-KeySales, subscriptions, refundsPushed in real time

Setting it up

Use this option to track revenue from any platform — JTL Shop, Shopify, WooCommerce, Lemon Squeezy, custom checkouts, mobile apps, etc. You POST each transaction to Swetrix as it happens.

You don't have to set anything up in Project Settings > Revenue first — sending your first transaction automatically enables API revenue tracking for the project and locks in the display currency you sent. You can change it later from the settings page.

Get your API key

Open your account settings and copy your personal API key. It's the same key used for the Statistics API.

Treat the key like a password — never embed it in client-side code. The endpoint must be called from your backend.

POST a transaction

Send a request to https://api.swetrix.com/log/revenue for every sale, refund, or recurring charge. Pick the example below that matches your stack.

curl -X POST https://api.swetrix.com/log/revenue \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: YOUR_API_KEY" \
  -d '{
    "pid": "YOUR_PROJECT_ID",
    "transactionId": "order_42891",
    "type": "sale",
    "amount": 49.99,
    "currency": "EUR",
    "productName": "Pro plan (yearly)",
    "profileId": "user-12345"
  }'

Drop this into a webhook handler that fires when an order is paid. The same shape works for any PHP-based shop — WooCommerce, custom Symfony / Laravel checkouts, etc.

<?php

$payload = [
    'pid'           => 'YOUR_PROJECT_ID',
    'transactionId' => $order->id,
    'type'          => 'sale',
    'amount'        => (float) $order->total,
    'currency'      => $order->currency,
    'productName'   => $order->lineItems[0]->name ?? null,
    'profileId'     => $order->customerId,
];

$ch = curl_init('https://api.swetrix.com/log/revenue');
curl_setopt_array($ch, [
    CURLOPT_RETURNTRANSFER => true,
    CURLOPT_POST           => true,
    CURLOPT_HTTPHEADER     => [
        'Content-Type: application/json',
        'X-Api-Key: YOUR_API_KEY',
    ],
    CURLOPT_POSTFIELDS     => json_encode($payload),
]);

curl_exec($ch);
curl_close($ch);
await fetch("https://api.swetrix.com/log/revenue", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "X-Api-Key": process.env.SWETRIX_API_KEY,
  },
  body: JSON.stringify({
    pid: "YOUR_PROJECT_ID",
    transactionId: order.id,
    type: "sale",
    amount: 49.99,
    currency: "EUR",
    productName: "Pro plan (yearly)",
    profileId: user.id,
  }),
});

Record refunds

Send a second request with "type": "refund" and the same transactionId shape you'd use for a sale. Always send a positive amount — Swetrix stores it as a negative value automatically so net revenue and the refunds chart line both come out right.

curl -X POST https://api.swetrix.com/log/revenue \
  -H "Content-Type: application/json" \
  -H "X-Api-Key: YOUR_API_KEY" \
  -d '{
    "pid": "YOUR_PROJECT_ID",
    "transactionId": "refund_for_order_42891",
    "type": "refund",
    "amount": 49.99,
    "currency": "EUR"
  }'

Request fields

FieldTypeRequiredDescription
pidstringyesYour Swetrix project ID.
typesale | refund | subscriptionyesTransaction type. Use refund for refunds — the amount sign is handled automatically.
amountnumberyesAmount in major units (e.g. 49.99 for €49.99). Always send a positive number.
currencystringyesISO 4217 currency code (e.g. USD, EUR). Converted to your project's display currency automatically.
transactionIdstringnoStable unique identifier. Re-sending the same transactionId replaces the previous version (idempotent). If omitted, a UUID is generated.
productIdstringnoOptional SKU / product identifier.
productNamestringnoOptional human-readable product name shown in the transactions table.
profileIdstringnoProfile ID for revenue attribution. Same value you'd pass to swetrix.init({ profileId }).
sessionIdstringnoSession ID for attributing revenue to a specific browsing session (from getSessionId()).
createdISO 8601 stringnoTransaction date. Defaults to the time Swetrix receives the request — useful when backfilling.
metadataobjectnoArbitrary string key/value pairs stored alongside the transaction (max 100 keys, 2 KB total).

Idempotency. If your platform might retry webhooks (most do), pass a stable transactionId like the order ID. Re-sending the same transactionId updates the existing record instead of creating a duplicate.

Open the Revenue settings

Go to your project dashboard and open Project Settings > Revenue, then select Stripe as the provider.

Create a restricted API key

The settings page includes a direct link to create a Stripe restricted key with the correct permissions pre-selected — just click "Create key on Stripe" and confirm.

Swetrix needs the following read-only permissions:

  • Charges, Subscriptions, Customers, Payment Intents, Checkout Sessions, Invoices, Products (read)
  • Webhooks (write — for real-time sync)

Connect

Paste the restricted key (starts with rk_live_) into the API key field, choose your display currency, and click Connect. Swetrix converts all transactions to this currency automatically.

Open the Revenue settings

Go to your project dashboard and open Project Settings > Revenue, then select Paddle as the provider.

Generate a Paddle API key

In your Paddle dashboard, create an API key with the following read-only permissions:

  • Transactions, Subscriptions, Customers, Products, Prices (read)

Connect

Paste the API key (starts with pdl_live_) into the API key field, choose your display currency, and click Connect.

Viewing revenue data

Once connected, a Revenue metric becomes available in the Traffic Analytics chart. Toggle it on using the metric selector above the chart.

The chart displays:

  • Revenue — total net revenue for each time bucket (hour, day, week, etc.)
  • Refunds — refund amounts stacked on top for visual comparison

You can combine revenue with any other metric (pageviews, sessions, etc.) and use all standard dashboard features: date ranges, comparisons, filters, and segments.

User attribution

Swetrix can attribute revenue to specific visitors using profile IDs. This lets you see which users generated revenue and connect purchases to browsing sessions.

Getting the profile ID

First, get the visitor's profile ID using the Swetrix script:

const profileId = await swetrix.getProfileId();

You can also pass swetrix_session_id (from getSessionId()) to attribute revenue to a specific browsing session.

Passing it through to Swetrix

Pass profileId and sessionId directly in the request body when you POST the transaction:

await fetch("https://api.swetrix.com/log/revenue", {
  method: "POST",
  headers: {
    "Content-Type": "application/json",
    "X-Api-Key": process.env.SWETRIX_API_KEY,
  },
  body: JSON.stringify({
    pid: "YOUR_PROJECT_ID",
    transactionId: order.id,
    type: "sale",
    amount: 49.99,
    currency: "EUR",
    profileId,
    sessionId,
  }),
});

When Swetrix syncs Stripe transactions, it looks for swetrix_profile_id (and optionally swetrix_session_id) in metadata on the PaymentIntent or Charge.

const paymentIntent = await stripe.paymentIntents.create({
  amount: 2000,
  currency: "usd",
  metadata: {
    swetrix_profile_id: profileId,
  },
});

When Swetrix syncs Paddle transactions, it looks for swetrix_profile_id (and optionally swetrix_session_id) in custom_data on the Transaction.

Paddle.Checkout.open({
  items: [{ priceId: "pri_xxxxx", quantity: 1 }],
  customData: {
    swetrix_profile_id: profileId,
  },
});

If a profile ID is found, the transaction is linked to that visitor's profile in the Profiles & Sessions view.

See the Script Reference for full details on getProfileId() and getSessionId().

Managing your connection

You can disconnect or change your revenue source at any time from Project Settings > Revenue. Disconnecting removes the API key (or disables API ingestion) but keeps previously recorded revenue data in your dashboard.

To change the display currency after connecting, use the currency selector on the same settings page. Currency conversion is applied to all transactions (past and future) based on exchange rates at sync time.

A project can only have one active revenue source at a time. If a Stripe or Paddle key is connected and you try to POST to /log/revenue, the request returns 409 Conflict. Disconnect the existing source first.

On this page