# Trace every paid order to its channel

> Add MIRA FIVE to a Laravel app with one Composer package, the script tag in your Blade layout and paid orders sent from your controllers.

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

One Blade directive counts every visit, and the Mira facade reports each paid order after the response.

Package `mirafive/sdk-laravel`

## Set up in 5 steps

1. ### Install the package  
The service provider and the `Mira` facade are discovered automatically, so there is nothing to register. It needs PHP 8.3 or later and Laravel 11, 12 or 13.  
```  
composer require mirafive/sdk-laravel  
```
2. ### Add the two keys  
The secret key of a server source sends events from your app and never reaches a page. The website key of a website source goes into the script tag. Both are under **Data → Sources**.  
```  
MIRAFIVE_SECRET_KEY=mf_…  
MIRAFIVE_WEBSITE_KEY=mf_…  
```
3. ### Add the script to your layout  
`@mirafiveScript` prints the two-line script tag with your website key, and a Vite CSP nonce when one is set. It counts every page and starts without cookies.  
```  
<head>  
    @mirafiveScript  
</head>  
```
4. ### Send the paid order  
Call the facade where your app marks the order as paid, such as the payment webhook. `track` buffers, and the package sends after the response, so the page never waits.  
```  
use MiraFive\Laravel\Facades\Mira;  
Mira::track('order_paid', userId: (string) $order->user_id, properties: [  
    'revenue' => 328,  
    'currency' => 'EUR',  
]);  
```
5. ### Check the setup  
The check command sends a test event that is never stored or billed, and ends with "The key and host work." Then open a page on its real domain and watch **Data → Live**.  
```  
php artisan mirafive:check  
```

MIRA FIVE is analytics built around the person. In a Laravel app one Composer package covers both sides: a Blade directive for the browser, and a facade that sends paid orders from your server.

## 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 Paid search 240 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.

The default script 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. Switch the website source to **Full** under **Data → Sources**. Then switch the script to full mode, pass your banner’s answer, and identify signed-in visitors with the same id your server sends:

```sh
MIRAFIVE_SCRIPT_MODE=full
```

```blade
<head>
    @mirafiveScript
    @auth
        <script>mirafive('identify', @json((string) auth()->id()))</script>
    @endauth
</head>
```

In full mode the script sends and stores nothing until the visitor answers, and nothing for visitors who decline. Your banner passes the answer with `mirafive('consent', …)`: `true` for statistics only, `false`, or `{ statistics, experiments, targeting }`. The paid order then carries the same user id, and MIRA FIVE puts it on that person, next to the channel of their first visit.

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 make a webhook count once?

Payment providers sometimes deliver a webhook twice. `Mira::send` goes out at once with an idempotency key and returns a receipt, so a repeat is stored once:

```php
use MiraFive\Laravel\Facades\Mira;

Mira::send([
    ['name' => 'order_paid', 'userId' => (string) $order->user_id, 'properties' => ['revenue' => 328, 'currency' => 'EUR']],
], idempotencyKey: "order-{$order->id}");
```

Server events and the script have separate modes: `MIRAFIVE_MODE` for server events (full by default) and `MIRAFIVE_SCRIPT_MODE` for the tag (consentless by default). Your site decides the lawful basis for the user ids it sends.

## Can I read feature flags?

Yes. `Mira::forUser()` reads the signed-in user’s [feature flags](https://mirafive.io/glossary/feature-flag) in your process, and takes the opt-out from the current request:

```php
use MiraFive\Laravel\Facades\Mira;

$flags = Mira::forUser($request->user())->flags();

if ($flags->enabled('new-checkout')) {
    // the new checkout
}
```

`@mirafiveFlags` renders the same answers into the page, so the browser starts from them and the first paint shows the right variant. A code [A/B test](https://mirafive.io/glossary/ab-test) is a flag read the same way. The [Laravel SDK docs](https://docs.mirafive.io/sdks/laravel) cover queues, Octane and testing.

## Other setups

The same numbers, whichever way your site is built.

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

### Does tracking slow down my responses?

No. Buffered events leave after the response, and after each Octane request and queued job. With MIRAFIVE\_QUEUE set, each batch goes to a queue worker instead.

### How do I test code that sends events?

Call Mira::fake() in the test. It records instead of sending, and assertTracked('order\_paid') checks the event. Input MIRA FIVE would refuse still fails the test.

### Which versions are supported?

PHP 8.3 or later and Laravel 11, 12 and 13\. The package wraps the PHP SDK, mirafive/sdk-php, and works with Octane.

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