# Where your React app's buyers come from

> Add MIRA FIVE to a React app with createMira and one provider, then send paid orders from your server to see which channel brings the buyers.

URL: https://mirafive.io/for/react  
Updated: 2026-09-28

One client and one provider count every navigation, and your server reports the orders that paid.

Package `@mirafive/sdk-react`

## Set up in 5 steps

1. ### Install the packages  
The React SDK sits on top of the browser SDK, so you install both. It works with React 18.3 and 19.  
```  
npm install @mirafive/sdk-react @mirafive/sdk-browser  
```
2. ### Create the client  
Put the website key of your website source from **Data → Sources** in `VITE_MIRAFIVE_KEY`, or your bundler's public variable. Create the client once in the browser entry and wrap the app in `MiraProvider`. `pageviews()` counts every navigation for any router, so you add no router hook.  
```  
import { createMira } from '@mirafive/sdk-browser'  
import { flags } from '@mirafive/sdk-browser/flags'  
import { pageviews } from '@mirafive/sdk-browser/pageviews'  
import { MiraProvider } from '@mirafive/sdk-react'  
import { createRoot } from 'react-dom/client'  
import { App } from './App'  
const mira = createMira({  
  key: import.meta.env.VITE_MIRAFIVE_KEY,  
  plugins: [pageviews(), flags()],  
})  
createRoot(document.getElementById('root')!).render(  
  <MiraProvider client={mira}>  
    <App />  
  </MiraProvider>,  
)  
```
3. ### Record what matters  
Call `track` from any component inside the provider. Name the event after what happened; names that start with `$` are reserved.  
```  
import { useMira } from '@mirafive/sdk-react'  
export function AddToCart() {  
  const mira = useMira()  
  return <button onClick={() => mira.track('added_to_cart', { product: 'merino-crew' })}>Add to cart</button>  
}  
```
4. ### Send the paid order from your server  
Record the purchase where the payment is confirmed, with `@mirafive/sdk-server` and the secret key of a server source. The key stays on the server, and the `revenue` property feeds your purchase goal.  
```  
import { Mira } from '@mirafive/sdk-server'  
const mira = new Mira({ key: process.env.MIRAFIVE_SECRET_KEY })  
// Where your backend confirms the payment  
mira.track('order_paid', {  
  userId: order.customerId,  
  properties: { revenue: 328, currency: 'EUR' },  
})  
```
5. ### Check the live view  
Deploy, open a page on your site and watch **Data → Live**, which refreshes every 5 seconds. Events from localhost are dropped unless you pass `trackLocalhost: true` to `createMira`.

MIRA FIVE is analytics built around the person. In a React app it takes one client and one provider in the browser, and your server adds the paid orders, so every buyer leads back to the channel that brought them.

## What will I see after installing?

The first three questions the dashboard answers, from the default setup:

1. **Which channels send visitors?** Acquisition › Channels splits visits into nine channels, from paid search and email to AI assistants such as ChatGPT. In the sample shop, Direct sent 525 visits, Organic search 438 and Email 170 over 30 days.
2. **Which pages do they land on?** Journeys › Pages lists every route with pageviews, entries, bounce rate, exits and time on page. Sort by entries to see your landing pages.
3. **Which goals do they reach?** Goals counts every conversion of the events you send, such as a sign-up or a paid order.

The default setup sets no cookies, stores nothing on the device and sends no identifier.

## How does a paid order reach its channel?

Through the person who paid. With their consent, the browser keeps an id for the visitor, and `identify` ties it to your own user id when they sign in. Your server sends the order with the same user id, so MIRA FIVE puts the purchase on that person, next to their first visit and the channel that brought them.

Create a purchase goal for `order_paid`, and Acquisition shows buyers and revenue per channel and campaign. The guide [Which channel brings the customers who pay?](https://mirafive.io/learn/which-channel-brings-paying-customers)reads those numbers.

## How do I collect with consent?

Switch the website source to **Full** under **Data → Sources**. Then switch the client to full mode and add the `identity()` plugin:

```tsx
import { identity } from '@mirafive/sdk-browser/identity'

const mira = createMira({
  key: import.meta.env.VITE_MIRAFIVE_KEY,
  mode: 'full',
  plugins: [pageviews(), identity(), flags()],
})
```

Then pass your banner’s answer and the signed-in user:

```tsx
const mira = useMira()

// From your consent banner's callback
mira.consent({ statistics: true, experiments: true, targeting: false })

// After sign-in, with your own user id
mira.identify(user.id, { plan: user.plan })

// After sign-out
mira.reset()
```

Before an answer, full mode stores and sends nothing. `consent(true)` grants statistics only, and `consent(false)` forgets the ids. Ids live in localStorage, never in cookies. The [consent guide](https://docs.mirafive.io/guides/consent) explains the three scopes.

## How do I make a webhook count once?

Payment providers sometimes deliver a webhook twice. `send` delivers at once and takes an idempotency key, so a repeat is stored once:

```ts
await mira.send(
  [{ name: 'order_paid', userId: order.customerId, properties: { revenue: 328, currency: 'EUR' } }],
  { idempotencyKey: `order-${order.id}` },
)
```

`track` buffers and sends within a second. In a function that ends early, `await mira.flush()` before it returns. The [server-side guide](https://docs.mirafive.io/guides/server-side) covers each runtime.

## Can the same client read feature flags?

Yes, through the `flags()` plugin from step 2\. `useFlag('new-checkout', false)` returns the variant, or `true` and `false` for an on/off [feature flag](https://mirafive.io/glossary/feature-flag), and `useFlagConfig` returns a remote-config value. A code [A/B test](https://mirafive.io/glossary/ab-test) is a flag your app reads the same way. The [React SDK docs](https://docs.mirafive.io/sdks/react) cover server rendering.

## Other setups

The same numbers, whichever way your site is built.

- [Astro](https://mirafive.io/for/astro)
- [Next.js](https://mirafive.io/for/nextjs)
- [Laravel](https://mirafive.io/for/laravel)
- [Nuxt](https://mirafive.io/for/nuxt)
- [Symfony](https://mirafive.io/for/symfony)
- [PHP](https://mirafive.io/for/php)
- [Vue](https://mirafive.io/for/vue)
- [TanStack Start](https://mirafive.io/for/tanstack-start)
- [Node.js](https://mirafive.io/for/nodejs)
- [Convex](https://mirafive.io/for/convex)
- [JavaScript](https://mirafive.io/for/javascript)
- [any website](https://mirafive.io/for/website)

[Read the docs](https://docs.mirafive.io)

## Questions and answers

### Do I need a router hook for pageviews?

No. The pageviews() plugin records the first page and every client-side navigation through the Navigation API or the History API, whichever router you use.

### Can I send an event when a component mounts?

Yes. useTrackOnMount(name, properties) sends one event when the component appears, and only once under StrictMode too.

### I build with Next.js. Is this the right package?

No. Use @mirafive/sdk-next, which creates the client for you and adds the server side. The [Next.js setup](https://mirafive.io/for/nextjs) walks through it.

## See which channel brings buyers

Free for 25,000 events a month. No card needed.

[Start free](https://app.mirafive.io/register)[See pricing](https://mirafive.io/pricing)
