# PostHog

Source: https://developers.swell.is/app-guides/posthog

The PostHog app sends your store's orders, payments, refunds and subscription changes to PostHog as they happen. Events come from Swell, not the shopper's browser, so ad blockers can't drop them, and each one is tied to the customer's PostHog profile.

The app works with PostHog Cloud, in the US or EU, and with self-hosted PostHog.

## How it works

| When | What the app does |
| --- | --- |
| A customer places an order | Sends Order Completed, with the totals, discount, coupon, currency and products. |
| An order is canceled or fully fulfilled | Sends Order Cancelled, or Order Delivered if you turn it on. |
| A payment is captured | Sends Payment Completed with the amount as revenue, for orders, invoices and subscriptions alike. |
| A refund succeeds | Sends Order Refunded with the amount as negative revenue, for partial refunds too. |
| A subscription starts, renews, fails to pay or is canceled | Sends Subscription Started, Renewed, Payment Failed or Cancelled. |
| A subscription is paused or resumed | Sends Subscription Paused or Resumed, if you turn them on. |

## Before you begin

- A PostHog project, on PostHog Cloud or self-hosted.
- For the test environment, a separate PostHog project, so test orders stay out of your live data.

## Set up

Install PostHog from the Swell App Store, and set it up in your test environment before the live one.

**1. Copy your project API key**

In PostHog, open **Project settings** and copy the **Project API key**, which starts with `phc_`. This key can only send events. It can't read your PostHog data.

**2. Add it to the app**

In Swell, go to **Apps > PostHog > Settings** and paste the key in **Project API key**. Under **PostHog region**, choose **US Cloud** or **EU Cloud** to match your PostHog project. For self-hosted PostHog or a proxy, choose **Self-hosted or proxy** and enter its full address, including `https://`, in **PostHog URL**. Click **Save settings**. Events are sent from then on.

**3. Send a test event**

Click **Send test event**. A **Swell Test Event** appears in PostHog under **Activity**, from a person named `swell-test-` and your store ID, which you can delete. If the key, region or address is wrong, the message says what to fix.

Check the key this way: events sent with a wrong project API key are accepted by PostHog and then dropped, so nothing else shows the mistake.

**4. Choose the events**

Under **Orders**, **Revenue** and **Subscriptions**, turn on the events to send, and click **Save settings**. Order Delivered, Subscription Paused and Subscription Resumed are off at first. The rest are on.

**5. Set up revenue analytics**

This step is optional. In PostHog, go to **Data management > Revenue** and choose **Add Revenue Event**. Pick **Payment Completed** as the event, `revenue` as the **Revenue Property** and `currency` as the **Dynamic Currency Property**, and turn on **Values are in cents**. Do the same for **Order Refunded**.

**6. Place a test order**

Place a test order and pay for it. Within a few seconds, PostHog shows **Order Completed** under **Activity**, on the customer's profile, and **Payment Completed** once the payment is captured.

**7. Go live**

Settings are saved separately for each environment. In the live environment, repeat steps 2 to 4 with the key of your live PostHog project, and step 5 in that project.

## Using PostHog

### Events

Each event carries the properties below, plus `swell_store_id`. Properties without a value in Swell are left out, except `guest` and `trial`, which are always true or false.

| Event | Sent when | Properties |
| --- | --- | --- |
| Order Completed | A customer places an order. | order_id, order_number, total, subtotal, shipping, tax, discount, coupon, currency, guest, products. Each product has product_id, variant_id, name, variant, price and quantity. |
| Order Cancelled | An order is canceled. | The same as Order Completed. |
| Order Delivered | An order is fully fulfilled. Off at first. | order_id, order_number |
| Payment Completed | A payment succeeds. Payments authorized first are sent when they're captured. Gift card and store credit payments aren't sent. | revenue, currency, order_id, invoice_id, subscription_id, payment_id, payment_method |
| Order Refunded | A refund succeeds, partial ones included. Refunds of gift card and store credit payments aren't sent. | revenue (negative), currency, order_id, subscription_id, refund_id, payment_id, reason |
| Subscription Started | A customer starts a subscription, trials included. Draft subscriptions aren't sent. | subscription_id, plan_id, plan, product_id, product, variant, price, recurring_total, currency, interval, interval_count, trial |
| Subscription Renewed | A subscription is charged for a new period. The first payment, made with the order, isn't a renewal. | The same as Subscription Started. |
| Subscription Payment Failed | A subscription charge fails. | The same as Subscription Started. |
| Subscription Cancelled | A subscription is canceled. | The same as Subscription Started, plus cancel_reason. |
| Subscription Paused | A subscription is paused. Off at first. | The same as Subscription Started. |
| Subscription Resumed | A paused subscription is resumed. Off at first. | The same as Subscription Started. |

### Customers

Each event's person in PostHog is the Swell customer, identified by their Swell customer ID. Every event also sets the person's `email`, and their `name` when the customer has one, so PostHog shows them by email. Orders from guest checkouts have `guest` set to true.

### Revenue

Only Payment Completed and Order Refunded carry revenue, in the currency's smallest unit, such as cents. Every charge is one payment, whatever it pays for, so revenue is counted once. Orders and subscription events have totals and prices but no revenue.

Gift card and store credit payments aren't counted, because that money was counted when the gift card was bought or the credit was earned.

### Event times and retries

Each event has the time it happened in Swell, not the time it was sent. When Swell sends an event again after an error, it has the same event ID, so PostHog keeps only one.

### In the dashboard

| Where | What it's for |
| --- | --- |
| Apps > PostHog > Settings | The project API key, the region or address, Send test event, and the events to send. |

## Settings

Settings are in **Apps > PostHog > Settings** and are saved separately for each environment.

| Setting | Description | Default |
| --- | --- | --- |
| Project API key | From PostHog > Project settings. Starts with phc_. Required. | None |
| PostHog region | US Cloud, EU Cloud, or Self-hosted or proxy. | US Cloud |
| PostHog URL | For Self-hosted or proxy only. The full address of your PostHog, including https://. | None |
| Send test event | Sends one Swell Test Event to check the connection. Save the settings first. |  |
| Orders | Order completed, Order cancelled, Order delivered. | On, on, off |
| Revenue | Payment completed, Refund. | On, on |
| Subscriptions | Subscription started, renewed, payment failed, cancelled, paused, resumed. | On, on, on, on, off, off |

## Limitations

- Events are sent from when you save the project API key. Past orders, payments and subscriptions aren't imported.
- The app sends store events only. To see storefront visits and page views, add PostHog's own snippet to your storefront.
- Events are sent from Swell's servers, so PostHog doesn't add a location to them.
- Event names are fixed.
- If PostHog is down or rate-limits the app, Swell sends the event again later. Other errors are logged and the event isn't sent again.
- PostHog accepts events sent with a wrong project API key and then drops them, so the app can't report it. Use **Send test event** to check the key.
- If PostHog keeps failing for about 4 days, Swell turns off the app's event function and emails the store's admins. Reinstall the app to turn it back on.

## Troubleshooting

The app logs each event PostHog rejects. In the Swell dashboard, the logs are under **Developer > Console > Logs**.

### "PostHog rejected this project API key"

Copy the key again from **Project settings** in PostHog. It starts with `phc_`. A personal API key doesn't work here. Also check that **PostHog region** matches your project: a key from a US Cloud project is rejected by EU Cloud.

### "Could not reach PostHog"

PostHog didn't answer, or answered with a server error or a rate limit. For self-hosted PostHog or a proxy, check that **PostHog URL** is the full address, including `https://`. Otherwise, try again in a few minutes.

### "Enter your PostHog project API key"

Enter the key, and for self-hosted PostHog a full address in **PostHog URL**, then click **Save settings** before **Send test event**.

### Events don't appear in PostHog

Click **Send test event** to check the key and region. Then check that the event is turned on in the app settings. Events are sent only for changes made after the key was saved, and Payment Completed only once a payment is captured.

### Revenue is 100 times too high

The app sends revenue in cents. In PostHog, turn on **Values are in cents** for Payment Completed and Order Refunded under **Data management > Revenue**.

## Uninstalling

Uninstalling the app stops sending events to PostHog. Uninstalling applies to the environment you are in, so remove the app from the test and live environments separately.

Events and person profiles already in PostHog stay there.

## For developers

| Function | Runs on | What it does |
| --- | --- | --- |
| posthog-capture | order.submitted, order.canceled, order.delivered, payment.succeeded, payment.refund.succeeded, subscription.created, subscription.paid, subscription.payment_failed, subscription.canceled, subscription.paused and subscription.resumed | Reads the record and the customer, and sends one event to PostHog. |
| posthog-test | The Send test event button | Checks the key and sends a Swell Test Event. |

Events go to the PostHog capture API at `/i/v0/e/` on the chosen host. The `distinct_id` is the Swell account ID, and each event has `$set` with the customer's `email` and `name`, `$geoip_disable` set to true, and `swell_store_id`. The `uuid` is derived from the Swell event ID and the `timestamp` comes from it, so a retried delivery is deduplicated. Network errors, timeouts, 429 and 5xx responses, and Swell API errors other than 404, make Swell retry the event. Other 4xx responses are logged and not retried, and records deleted since the event are skipped.

## Support

Swell builds and maintains the PostHog app. For help with the app, email support@swell.is. For questions about your PostHog account or project, contact PostHog.
