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

# Server-Side Events Overview

> Send secure conversion events directly from your backend — purchases, sign-ups, leads — attributed to the QR Code scan that started the user journey.

Server-side events let your backend report conversions directly to the Scanova Tracking API using an API key. Unlike browser events, server events cannot be blocked by ad blockers, are not affected by browser restrictions, and can carry sensitive attribution data securely.

## When to use server events

| Use browser events                | Use server events                   |
| --------------------------------- | ----------------------------------- |
| Page views and navigation         | Purchase confirmations              |
| Clicks and scroll depth           | Subscription activations            |
| Form field interactions           | Lead creation in your CRM           |
| Any action visible in the browser | Sign-up email verifications         |
| —                                 | Any action that happens server-side |

Use both together for the fullest picture: the browser SDK tracks the journey, and your server reports when a conversion actually happened.

## How attribution works server-side

The `scan_session_id` is the attribution link between a QR scan and a server event. Here is the typical flow:

```
User scans QR Code
    ↓
Lands on yoursite.com/?scnv=7ad26d4f-...
    ↓
SDK saves scan_session_id to localStorage
    ↓
User completes a purchase form
    ↓
Browser sends scan_session_id to your checkout API
    ↓
Your server sends a purchase event with that scan_session_id
    ↓
Scanova attributes the purchase to the QR scan
```

**Your responsibility:** pass the `scan_session_id` from the browser to your server. Common ways to do this:

* Include it in a hidden form field
* Send it in the API request body from your frontend JavaScript
* Store it in the user's session on your server (read it from the URL parameter when the page loads)

```javascript theme={null}
// Read from SDK (browser-side)
// Note: _scnv is the SDK's internal storage key — structure may change.
// Use this pattern only if no higher-level SDK method is available.
const scanSessionId = localStorage.getItem('_scnv')
  ? JSON.parse(localStorage.getItem('_scnv')).sid
  : null;

// Include in your API call to your backend
await fetch('/api/checkout', {
  method: 'POST',
  body: JSON.stringify({ ...orderData, scan_session_id: scanSessionId })
});
```

## Requirements

* A tracking site created in **Integrations → Conversion Tracking**
* A site-scoped API key (generated in the tracking site's **API Keys** tab)
* Your server can make outbound HTTPS POST requests
* You have a way to receive the `scan_session_id` from the user's browser

## Security requirements

* **Never expose your API key in frontend code or client-side JavaScript**
* Store the key in an environment variable or secrets manager
* Rotate keys periodically from the dashboard

## Next steps

<CardGroup cols={2}>
  <Card title="Generate an API Key" icon="key" href="/conversion-tracking/server/generate-api-key-dashboard">
    Create a site-scoped API key from the dashboard.
  </Card>

  <Card title="Send Events" icon="paper-plane" href="/conversion-tracking/server/send-events">
    Code examples in cURL, Node.js, Python, and PHP.
  </Card>

  <Card title="Idempotency & Retries" icon="rotate" href="/conversion-tracking/server/idempotency-retries">
    How to safely retry failed requests.
  </Card>

  <Card title="Verify Delivery" icon="check" href="/conversion-tracking/server/verify">
    Confirm your events are being received.
  </Card>
</CardGroup>
