Sessions · Getting started
Quickstart
From a new project to your first recording. You need a Laravel 12 or 13 app on PHP 8.2 or later, and a way to ask your visitors for their yes.
1. Choose a plan
At id.my-beast.com, pick Sessions and a package, name your project and pay. Masking is required in your production environments from the start.
Then open the project in Sessions at services.my-beast.com. Until Sessions hears your app, the project's Overview is its setup guide: the same steps as below, with your project's own keys and where it stands on each.
2. Install the SDKs
One package on each side. In your app's folder:
composer require mybeast/sessions-laravel
npm install @mybeast/sessionsmybeast/sessions-laravel signs the token each page carries and sends the journey. @mybeast/sessions records the page in the browser, masked before anything leaves it. Until their .env lines are in, both stay off and your app runs as before.
3. Add the keys to .env
MYBEAST_SESSIONS_URL=https://services.my-beast.com/sessions
MYBEAST_SESSIONS_PUBLIC_KEY=pk_…
MYBEAST_SESSIONS_SIGNING_KEY=sig_…
MYBEAST_SESSIONS_SECRET=sk_…
MYBEAST_SESSIONS_ENVIRONMENT=production- The public key (
pk_…) names the project in the browser. It's not a secret. - The signing key (
sig_…) stays on your server and signs each page's token. - The server secret (
sk_…) sends the journey and the key flows, and asks for erasure. Recordings alone don't need it.
The setup guide shows your project's values. The signing key is shown again in Settings → Keys; a server secret only once, when it's made. When id made the keys with your project, Secrets keeps the URL and the three keys in each environment, so an app that takes its .env from Secrets has them already.
MYBEAST_SESSIONS_ENVIRONMENT isn't in Secrets: each copy of your app sets its own, one of your project's environments, and each keeps its recordings apart. Left out, the SDK uses APP_ENV.
Keep two of the keys on the server
4. List your app's origins
A page sends recordings only from an origin the project lists: the scheme, the host and the port, as the address bar shows them. Add each address your app runs at in Settings → Browser origins, your own machine's too, such as http://localhost:8000. Plain http works only on a developer's machine: localhost, 127.0.0.1, [::1], *.localhost and *.test.
From an origin that isn't listed, the browser gets no answer and nothing arrives.
5. Hand each page its config
Your server makes each page's config with Sessions::clientConfig(): where to send, and a signed token saying whose recording it would be and whether the page may be recorded at all.
// app/Http/Middleware/HandleInertiaRequests.php
use MyBeast\Sessions\Laravel\Facades\Sessions;
public function share(Request $request): array
{
$user = $request->user();
return [
...parent::share($request),
// Ids only. No yes (null): this page is not recorded.
'sessions' => fn () => $user ? Sessions::clientConfig(
subject: $user->id,
account: $user->team_id,
consentAt: $user->recording_consent_at,
) : null,
];
}recording_consent_at stands for your own column: when the person said yes, as a date, and null until they do. With null, nothing is recorded. subject and account are ids of 1 to 64 letters, digits, dots, underscores, colons or hyphens, never an e-mail address: clientConfig() throws for anything else. account is optional: the person's team or workspace.
clientConfig() returns null while a .env line is missing or malformed, so a page without it simply isn't recorded.
6. Start the recorder
In the browser, once the page has its config:
import { router } from '@inertiajs/react'; // or '@inertiajs/vue3'
import { init, createRecorder } from '@mybeast/sessions';
// Once, in createInertiaApp's setup({ el, App, props }):
const page = props.initialPage;
// sessions: what Sessions::clientConfig() made (null: not recorded)
const recorder = createRecorder(init(page.props.sessions), {
dictionary: () => messages, // your UI strings: kept readable
currentPage: () => page.component,
});
recorder.start();
// Each visit brings a fresh token: hand it on before the page is drawn.
router.on('beforeUpdate', (event) => {
recorder.setToken(event.detail.page.props.sessions?.token ?? null);
});
// A visit changes the page without a page load.
router.on('navigate', (event) => recorder.pageChanged(event.detail.page.component));messages stands for your own UI strings: an array, or i18n objects such as i18next's, one per language. They're the only words a masked recording keeps readable. With no dictionary every word arrives as stars, which is safe and not broken. Keep your UI strings readable says more.
With Inertia, each visit brings a fresh token, so hand it on with recorder.setToken() before the page is drawn. A recording then outlives the token's 30 minutes, and someone who signs in after another person gets a recording of their own. A Blade app needs nothing more: each page load starts from its own token.
7. Check that Sessions hears your app
Sign in as someone who said yes (for a first try, your own account with its consent date set) and open a page. The recording's first chunk reaches Sessions within about five seconds, and the project's Overview turns into its dashboard.
Nothing arrives? Add onChange: (state) => console.log('sessions', state) to the recorder's options, reload, and read what it logs. Troubleshooting explains each answer.
8. Turn on the journey
Optional, and off until you switch it on. With the server secret in place, add this line beside the keys:
MYBEAST_SESSIONS_JOURNEY=trueThe SDK's middleware then joins your web group and keeps a step for each page shown or write taken by a signed-in person, once the answer has gone out, so it never slows a page. Steps are sent in batches after later answers, and every minute while Laravel's scheduler runs (php artisan schedule:work, or cron running schedule:run).
Next steps
- Record only with a yes: the token, the moment, and taking a yes back.
- Mask what a recording shows: your UI strings, private parts, and checking it before you ship.
- Follow the journey and define key flows.
- Erase a person's data when their account closes.