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
| Source | Connection method | Transaction types | Sync model |
|---|---|---|---|
| Stripe | Restricted API key (read-only) | Sales, subscriptions, refunds | Pulled every 30 min |
| Paddle | API key (read-only) | Sales, subscriptions, refunds (adjustments) | Pulled every 30 min |
| API (any platform) | POST /log/revenue + X-Api-Key | Sales, subscriptions, refunds | Pushed 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
| Field | Type | Required | Description |
|---|---|---|---|
pid | string | yes | Your Swetrix project ID. |
type | sale | refund | subscription | yes | Transaction type. Use refund for refunds — the amount sign is handled automatically. |
amount | number | yes | Amount in major units (e.g. 49.99 for €49.99). Always send a positive number. |
currency | string | yes | ISO 4217 currency code (e.g. USD, EUR). Converted to your project's display currency automatically. |
transactionId | string | no | Stable unique identifier. Re-sending the same transactionId replaces the previous version (idempotent). If omitted, a UUID is generated. |
productId | string | no | Optional SKU / product identifier. |
productName | string | no | Optional human-readable product name shown in the transactions table. |
profileId | string | no | Profile ID for revenue attribution. Same value you'd pass to swetrix.init({ profileId }). |
sessionId | string | no | Session ID for attributing revenue to a specific browsing session (from getSessionId()). |
created | ISO 8601 string | no | Transaction date. Defaults to the time Swetrix receives the request — useful when backfilling. |
metadata | object | no | Arbitrary 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.
Help us improve Swetrix
Was this page helpful to you?
