# Revenue

> Log purchases from your web app with the Grovs SDK.

Source: https://docs.grovs.io/docs/sdk/web/revenue

Log purchases to attribute revenue to links and campaigns, and see ARPU, LTV and per-product breakdowns in the dashboard.

> **Warning:** Purchase events need a **Grovs Enterprise** backend (`GROVS_EE=true`) on every platform. Grovs cloud runs Enterprise. On self-hosted Community edition the endpoint doesn't exist, and `logCustomPurchase` reports `eventDispatchFailed` naming the requirement instead of retrying.

## Setup

1. In the [Grovs dashboard](https://app.grovs.io), go to **Analytics → Revenue**.
2. Click **Enable Revenue Tracking**. Only instance admins can turn it on or off.

See [Revenue](https://docs.grovs.io/docs/revenue) for the dashboard and [Goals](https://docs.grovs.io/docs/revenue/goals) for revenue goals.

## Logging purchases

The web has no StoreKit or Play Billing, so every web payment is a custom purchase:

```javascript
await Grovs.logCustomPurchase({
  type: "buy",                  // "buy" | "cancel" | "refund" | "refund_reversed"
  priceInCents: 1999,
  currency: "USD",
  productID: "com.acme.coins.100",
  startDate: new Date(),        // optional, defaults to now
  transactionID: "order-8842",  // optional, but pass yours
});
```

Resolves `true` when the purchase was recorded. It resolves `false` without sending while the SDK is disabled, and before authentication completes (reported as `eventDispatchFailed`). A purchase that fails isn't stored for a later retry, so send it again with the same `transactionID`.

| Field           | Type              | Description                                                                  |
| --------------- | ----------------- | ---------------------------------------------------------------------------- |
| `type`          | `TransactionType` | `"buy"`, `"cancel"`, `"refund"` or `"refund_reversed"`                       |
| `priceInCents`  | `number`          | Amount in cents, for example `999` for $9.99                                 |
| `currency`      | `string`          | ISO 4217 currency code                                                       |
| `productID`     | `string`          | Your product identifier                                                      |
| `startDate`     | `Date`            | Transaction date. Defaults to now. An invalid date reports through `onError` |
| `transactionID` | `string`          | Your order or payment id. See below                                          |

### Transaction ids

The backend deduplicates on transaction id. Pass your own order or payment id and repeats are safe: a retry after a timeout or a double-submitted checkout counts once. If omitted, the SDK mints one per call. That covers its own network retries but can't recognize the same purchase sent from a later page load.

## Next steps

- [Track events and screens →](https://docs.grovs.io/docs/sdk/web/analytics)
- [Full API reference →](https://docs.grovs.io/docs/sdk/web/api-reference)
