> Meticulous records real user sessions from a web app and replays them against each commit to catch visual regressions.
>
> Full AI-readable docs index (complete project setup journey + every page as markdown): https://app.meticulous.ai/llms.txt

# Controlling when recording starts and stops

If you already server-side render your initial HTML, and have sufficient information when rendering the initial HTML to determine whether the
Meticulous recorder should record the session, then you can conditionally pre-render the Meticulous recorder script tag into your initial HTML.
In this case you can stop reading here.

If however you need to make frontend web requests to determine whether to start recording (for example fetching user data from an API), then you
can use [network-recorder.bundle.js](https://snippet.meticulous.ai/record/v1/network-recorder.bundle.js).

Meticulous needs to be able to record all network requests & responses from the very
start of your page load for a session to replay correctly. That means that if you only want to record sessions for certain users with
certain attributes then you have an issue: you need to wait for the user information to load before you know whether you can enable the
recorder, but if you enable the recorder after the user information has loaded then the recorder won't be able to capture the initial
request & response to load the user information, or other early network responses.

[network-recorder.bundle.js](https://snippet.meticulous.ai/record/v1/network-recorder.bundle.js) solves this: you include it in the HTML originally returned from the server for all sessions,
 and it'll temporarily record any network requests in memory (but _not_ send them to the server).

If when you load the user data you find out
 you _don't_ want to record the session then you can call the [`stopIntercepting()`](https://github.com/alwaysmeticulous/meticulous-sdk/blob/main/packages/recorder-loader/src/early-network-recorder.ts) method from
 `@alwaysmeticulous/recorder-loader`, and any recorded data will be discarded.

 If when you load the user
data you find out you _do_ want to record the session then you can call the [`tryLoadAndStartRecorder()`](https://github.com/alwaysmeticulous/meticulous-sdk/blob/main/packages/recorder-loader/src/loader.ts)
from `@alwaysmeticulous/recorder-loader`, at which point the data will start getting sent to the Meticulous servers. You can also
[stop recording part way through a session](#stop-recording-mid-session), whichever way you have installed the recorder.

## Setting up conditional recording using network-recorder.bundle.js

### Step 1: Add the network-recorder.bundle.js script tag

> **note**
> **Important: The Meticulous Recorder script should be the first script to load, and have no async or defer attributes**
>
> Libraries you depend on may snapshot references
> to `window.fetch` or `window.XMLHttpRequest` early in the page lifecycle, which means if Meticulous is not the first script to load
> it may not be able to record all the network
> responses required for your app to function ([learn more](/docs/how-to/ensure-recorder-captures-all-requests)). Therefore the recorder script
> must be the first script to load in order to be guaranteed to capture all network requests correctly. This means:
>
> 1. It should be added to your `index.html` file, before any other script tags.
> 2. It should not have any async or defer attributes set. If using NextJS then it should use the native `script` tag instead of the NextJS `Script` component.
> 3. It should be present in the initial HTML returned from the server -- you cannot add the script tag dynamically using JavaScript, since if
> you do so the browser may execute the script after other scripts have loaded. If you need to include the script tag in your HTML only
> in certain environments then this must be done either server-side, or at build time by templating your HTML.
>
> If it's not possible to meet these requirements then you can [use an NPM dependency instead of a script tag](#via-npm-dependency).

Add the [network-recorder.bundle.js](https://snippet.meticulous.ai/record/v1/network-recorder.bundle.js) script tag to your index.html, or the HTML returned from your server:

```html
<head>
  ...
  <script
    src="https://snippet.meticulous.ai/record/v1/network-recorder.bundle.js">
  </script>

  <!-- network-recorder.bundle.js should be added before your app -->
  ...
  <script src="main_app.js"></script>
</head>
```

### Step 2: Conditionally start recording

Load the data you need to determine whether to start recording. If you wish to record the session and start sending data to Meticulous then
call `tryLoadAndStartRecorder()`, otherwise call `stopIntercepting()`:

```typescript
import { tryLoadAndStartRecorder, stopIntercepting } from "@alwaysmeticulous/recorder-loader";

...

const user = await loadUser();
if (isNotProduction() && shouldRecord(user)) {
  // Note: all errors are caught and logged, so no need to surround with try/catch
  await tryLoadAndStartRecorder({
    recordingToken: '<RECORDING_TOKEN>',
    isProduction: false,
  });
} else {
  await stopIntercepting();
}
```

## Stop recording in the middle of the session

Once recording has started you can stop it at any point, whether you installed the recorder as an NPM package or as a script
tag. This is useful if you only find out part way through a session that you don't want to record it, for example because the
user has navigated into an area of your app that you'd rather not capture.

> **note**
> **Stopping recording is permanent for the current page load**
>
> Recording cannot be restarted after it has been stopped, unless the page is reloaded. Everything already uploaded is kept, and
> the session is flagged in Meticulous as having been stopped by your application. Anything recorded since the last upload is
> discarded, and no further data is sent to Meticulous's servers.

### NPM package

`tryLoadAndStartRecorder()` resolves to a recorder object with a `stopRecording()` method on it. Hold onto that object so that
you can stop recording later on:

```typescript
import { tryLoadAndStartRecorder } from "@alwaysmeticulous/recorder-loader";

// Start the Meticulous recorder before you initialise your app.
// Note: all errors are caught and logged, so no need to surround with try/catch
const recorder = await tryLoadAndStartRecorder({
  recordingToken: '<RECORDING_TOKEN>',
  isProduction: false,
});

// ...then later, at any point during the session:
await recorder.stopRecording();
```

If you are using `tryInstallMeticulousIntercepts()` instead then call the `stopRecording()` method returned by
`startRecordingSession()` in the same way.
### Script tag

There is no recorder object to hold onto when using a script tag, so instead call `stopRecording()` on the
`window.Meticulous` API that the recorder script sets up when it initialises:

```typescript
window.Meticulous?.record?.stopRecording();
```

Guard the call as above: `window.Meticulous` is not defined if the recorder script failed to load, or if recording was
disabled for this page load (for example by setting `window.METICULOUS_DISABLED`, or by adding a
`?_meticulousDisabled=true` query parameter to the URL). `record` is likewise absent while Meticulous is replaying the
session as a test, when there is nothing to stop -- in TypeScript, narrow on `isRunningAsTest` to reach it:

```typescript
if (window.Meticulous && !window.Meticulous.isRunningAsTest) {
  window.Meticulous.record.stopRecording();
}
```

## Alternative: using an NPM dependency

If you prefer to use an NPM dependency, rather than a script tag, you can instead use the [tryInstallMeticulousIntercepts() function](https://github.com/alwaysmeticulous/meticulous-sdk/blob/main/packages/recorder-loader/src/install-meticulous-intercepts.ts#L18
), instead of [network-recorder.bundle.js](https://snippet.meticulous.ai/record/v1/network-recorder.bundle.js). However this is not recommended since it's
 easy to miss network requests if libraries you use snapshot references to `window.fetch` or `window.XMLHttpRequest` early in the page
 lifecycle ([learn more](/docs/how-to/ensure-recorder-captures-all-requests)).

If when you load the user data you find out you _don't_ want to record the session then you can call the
`stopRecording()` method returned by `tryInstallMeticulousIntercepts()`, and any recorded data will be discarded. If when you load the user
data you find out you _do_ want to record the session then you can call the `startRecordingSession()` method returned
by `tryInstallMeticulousIntercepts()`, at which point the data will start getting sent to the Meticulous servers. You can then stop
recording a session at any point by calling the `stopRecording()` method returned by `startRecordingSession()`.

 Note: `tryInstallMeticulousIntercepts` will return a successful promise even if for some reason the browser is unable
 to load the required scripts, so it's safe, and indeed [required](/docs/how-to/ensure-recorder-captures-all-requests), to block your app loading on the promise returned by `tryInstallMeticulousIntercepts` resolving.
