# See which channel brings your Astro buyers

> Add MIRA FIVE to an Astro site with one integration bundled into your own build, and send paid orders from an endpoint to see buyers per channel.

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

One integration bundles the tracker into your own build, and an endpoint reports the orders that paid.

Package `@mirafive/sdk-astro`

## Set up in 5 steps

1. ### Install the packages  
Add the integration and the browser SDK it bundles. It works with Astro 7 and Node.js 22.12 or later.  
```  
npm install @mirafive/sdk-astro @mirafive/sdk-browser  
```
2. ### Add the integration  
Put the website key of your website source from **Data → Sources** in `PUBLIC_MIRAFIVE_KEY` in `.env`, then add the integration, or run `npx astro add @mirafive/sdk-astro`. Pageviews are sent on load and on every `<ClientRouter />` navigation.  
```  
import mirafive from '@mirafive/sdk-astro'  
import { defineConfig } from 'astro/config'  
export default defineConfig({  
  integrations: [mirafive()],  
})  
```
3. ### Record what matters  
Import `mirafive` from the client entry in any script or island and call a verb. A call made before the client starts is queued and runs once it does.  
```  
<button id="add-to-cart">Add to cart</button>  
<script>  
  import { mirafive } from '@mirafive/sdk-astro/client'  
  document.getElementById('add-to-cart')?.addEventListener('click', () => {  
    mirafive('track', 'added_to_cart', { product: 'merino-crew' })  
  })  
</script>  
```
4. ### Send the paid order from an endpoint  
The integration sends nothing from the server, so install `@mirafive/sdk-server` and use the secret key of a server source, read through `astro:env/server`. The endpoint renders on demand (`export const prerender = false`) and flushes before it returns.  
```  
import { Mira } from '@mirafive/sdk-server'  
import { getSecret } from 'astro:env/server'  
const mira = new Mira({ key: getSecret('MIRAFIVE_SECRET_KEY'), host: getSecret('MIRAFIVE_HOST') })  
// In the endpoint that confirms the payment  
mira.track('order_paid', {  
  userId: order.customerId,  
  properties: { revenue: 328, currency: 'EUR' },  
})  
await mira.flush()  
```
5. ### Check the live view  
Deploy, open a page on your site and watch **Data → Live**, which refreshes every 5 seconds. `astro dev` sends nothing unless you pass `dev: true`, so test on the deployed site.

MIRA FIVE is analytics built around the person, and the Astro integration is the quickest way in: one line in `astro.config`, and every page of the site is counted, including client-side navigation. An endpoint adds the paid orders, so you see which channel brings the people who buy.

## 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 organic search and paid social to email and AI assistants. In the sample shop, Direct sent 525 visits, Organic search 438 and Paid social 277 over 30 days.
2. **Which pages do they land on?** Journeys › Pages lists every page 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.

## 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. The endpoint 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 to [setting up a purchase goal](https://mirafive.io/learn/from-first-visit-to-paid-plan) walks through it.

## How do I collect with consent?

Switch the website source to **Full** under **Data → Sources**. Then set `mode: 'full'`, and the integration adds the identity code to the bundle:

```js
export default defineConfig({
  integrations: [mirafive({ mode: 'full' })],
})
```

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

```ts
import { mirafive } from '@mirafive/sdk-astro/client'

// From your consent banner
mirafive('consent', true) // statistics only
mirafive('consent', { statistics: true, experiments: true, targeting: false }) // by scope
mirafive('consent', false) // forgets what is stored on the device

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

// After sign-out
mirafive('reset')
```

Before an answer, full mode stores and sends nothing. Ids live in localStorage, never in cookies. The [Astro SDK docs](https://docs.mirafive.io/sdks/astro) show how to answer before the bundle loads.

## 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}` },
)
```

The [server-side guide](https://docs.mirafive.io/guides/server-side) covers retries and idempotency.

## Can I read feature flags?

Yes. Add `features: ['flags']` to the integration and read [feature flags](https://mirafive.io/glossary/feature-flag)inside the `flags` listener, which runs when they load or change:

```ts
mirafive('flags', () => {
  const newCheckout = mirafive('flag', 'new-checkout', false)
  document.body.classList.toggle('new-checkout', newCheckout === true)
})
```

On pages rendered on demand, `miraFlagsFor()` from `@mirafive/sdk-astro/server` answers them before the first paint. A code [A/B test](https://mirafive.io/glossary/ab-test) is a flag read the same way.

## Other setups

The same numbers, whichever way your site is built.

- [Next.js](https://mirafive.io/for/nextjs)
- [React](https://mirafive.io/for/react)
- [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

### What does the default setup collect?

Visits, pages, channels, campaigns, countries, devices and events. It sets no cookie, stores nothing on the device and sends no identifier. IP addresses are used to look up country and region and are never stored with your analytics data.

### Does the integration load a script from another domain?

No. It bundles the code into your own build, so the page loads it from your own origin. Events go to the MIRA FIVE collector at events.mirafive.io.

### Does it work with the ClientRouter?

Yes. The integration follows every ClientRouter navigation, holds the pageview until the new page has loaded, and sends it with that page's title and the right referrer.

## 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)
