---
title: "Why doesn't the Amplitude snippet load with Next.js's Script component, or why do events go missing right after a redirect?"
canonical_url: https://ampl.webclat.com/qa/amplitude-nextjs-script-tag-missing-events
description: "Two distinct Next.js failure modes for Amplitude: the Script component loading at the wrong strategy, and events queued right before a redirect never getting sent. Fixes for both."
source: Webclat | Amplitude Solutions (official Amplitude partner, independent consultancy)
---

# Why doesn't the Amplitude snippet load with Next.js's Script component, or why do events go missing right after a redirect?

**In short:** Next.js's Script component silently changes when and how a tag loads depending on its strategy prop - the wrong one (or none, defaulting to afterInteractive when your code assumes beforeInteractive) delays Amplitude's init past the point your code expects it to exist. Separately, events fired immediately before a client-side redirect can be lost because the page navigates away before the SDK's batched request finishes sending - two different bugs that produce the same symptom of "events just don't show up."

## Why this happens

Next.js's `next/script` component isn't a plain `<script>` tag - its `strategy` prop controls real, meaningfully different loading behavior: `beforeInteractive` runs before the page is interactive (blocking, similar to a classic head script), `afterInteractive` (the default) runs after hydration, and `lazyOnload` defers until the browser is idle. Code written assuming Amplitude is ready the moment the page renders, but loaded with the default `afterInteractive` strategy, can race against your own tracking calls - especially any tracking that fires during initial page load rather than in response to a later user action.

The `@next/third-parties/google` style convenience wrappers (and hand-rolled equivalents for other vendors) add another layer: if a project wraps Amplitude's own script tag in a similar helper, or nests it inside a client component that itself depends on hydration completing, the effective load timing shifts again relative to what a plain script tag in `_document` used to give pre-App-Router Next.js apps.

The redirect-related data loss is a separate, more fundamental issue: browsers are free to cancel in-flight network requests when a page unloads for a navigation, and Amplitude's SDK batches events for efficiency rather than sending each one the instant `track()` is called. If your code calls `track()` and then immediately triggers a client-side redirect (a router push, a `window.location` change, or a full-page navigation to an external URL like a payment provider) with no gap, the batched request can be still pending - not yet sent, or sent but not yet acknowledged - when the browser tears down the page context and drops it.

This shows up specifically "post-redirect" because the events lost are exactly the ones a redirect flow cares about most: a "Checkout Started" event fired right before sending the user to a payment page, or a "Signup Completed" event fired right before redirecting into the authenticated app - the most business-critical moments are also the ones most exposed to this race.

## Fix it

### Fixing Script component load timing

1. Decide what your tracking code actually needs: if any code path tracks something during the very first paint (rare, and usually better avoided), use `strategy="beforeInteractive"` and place the Script inside the root layout's `<head>` equivalent. For the much more common case of tracking user interactions after the page is usable, `afterInteractive` (or omitting strategy, since it's the default) is correct and does not need changing.
2. Wherever your own analytics wrapper module calls `amplitude.track()`, guard it against the SDK not being loaded yet regardless of Script strategy - check `typeof window !== "undefined" && window.amplitude` (or the equivalent for your import style) before calling, so a slow-loading script degrades to a skipped call instead of a thrown error.
3. If you're using the npm package (`@amplitude/analytics-browser`) rather than a CDN `<script>` tag at all, this entire failure mode doesn't apply - the package initializes as part of your JS bundle's normal execution, not as a separately-loaded, strategy-dependent script. Prefer the npm package over a Script-tag CDN load in a Next.js app for exactly this reason unless you have a specific reason not to.

### Fixing lost events around a redirect

1. For a client-side router navigation (Next.js `router.push`), insert a short, deliberate delay between the tracking call and the navigation - `await amplitude.track(eventName, props).promise` if your SDK version's track() returns a promise/result you can await, then navigate only after it resolves.
2. For a full-page navigation to an external destination (a payment provider, a third-party checkout), call `amplitude.flush()` (or the equivalent explicit-flush method in your SDK version) immediately before navigating, and if the SDK supports it, use `navigator.sendBeacon`-based transport for exactly this scenario - beacon requests are specifically designed by browsers to survive page unload, unlike a normal fetch/XHR.
3. Where the redirect is happening in response to a server action or a form submission rather than client-side JavaScript, consider firing the equivalent event server-side (via the HTTP API or Node SDK) instead of relying on a client-side call that has to win a race against navigation - a server-side send has no unload race to lose.

## How to verify it worked

1. For Script timing: add a console log immediately inside your first tracking call and compare its timestamp against a console log placed at the top of the Script's onLoad callback - the tracking call's timestamp should never be earlier than the script's load timestamp once the fix is in place.
2. For redirects: open the Network tab, throttle to a slow connection to widen the race window, trigger the redirect flow, and watch whether the Amplitude request shows as "finished" (not "cancelled" or still pending) before the navigation completes. A cancelled request confirms you're still losing the race.
3. In Amplitude's Events explorer, send a uniquely identifiable test event (a distinct event name or property value used only for this test) immediately before each redirect path you fixed, and confirm it appears in Amplitude - repeat several times, since a race condition can pass intermittently even when it's still present.
4. Compare your funnel completion counts for the specific step right before the redirect against the step right after, for a week before and a week after the fix - a step that previously showed an implausible drop specifically at the redirect boundary, and now doesn't, is the clearest real-world confirmation.

## FAQ

### Should I even be loading Amplitude via a Script tag in Next.js, or always use the npm package?

The npm package (@amplitude/analytics-browser) is the better default for a Next.js app specifically because it sidesteps the Script-strategy timing question entirely - it's bundled and initialized as ordinary JavaScript. A Script-tag CDN load makes sense mainly when you need to avoid adding the package to your JS bundle size, which is a narrower case than most teams are actually in.

### Does using sendBeacon for the pre-redirect event have any downsides?

Beacon requests have a smaller payload size limit than a normal request and don't return a response your code can read, so you lose the ability to confirm success client-side - which is an acceptable trade for a request that would otherwise have a meaningful chance of never being sent at all during a redirect.

Related: [Why does Amplitude intermittently throw "Invalid apiKey" or a runQueuedFunctions error?](https://ampl.webclat.com/qa/amplitude-invalid-apikey-sdk-not-ready), [Why does Amplitude fail to load with ERR_BLOCKED_BY_CLIENT, and how much of my traffic does that cost me?](https://ampl.webclat.com/qa/amplitude-blocked-by-ad-blockers), [What's the correct setup sequence to get Amplitude tracking events inside a React, React Native, or Expo app?](https://ampl.webclat.com/qa/integrate-amplitude-react-react-native-expo)
