Why does "_satellite is not defined" happen even though Adobe Launch is installed?

Quick answer

_satellite is the global object Adobe Launch's own library file creates once that file has finished loading and running - it does not exist a moment before that. The error almost always means your code called a _satellite.* method before the Launch library script had executed, not that the library is missing. Stop calling _satellite directly from arbitrary page code; route the event through the data layer and a Launch rule instead, or guard the call so it waits for the library.

Why this happens

Launch's embed code drops a script tag onto the page that fetches and executes a library file (the Development, Staging, or Production build for that property). By default that request does not block page rendering, so any application code that runs before the file has finished executing sees a page with no window._satellite object yet. A moment later, once the library finishes initializing, the object exists - the error is a timing race, not a missing dependency.

This shows up in three recurring shapes:

  • An inline <script> placed right after the Launch embed snippet calls _satellite.track(...) immediately, before the async request resolves.
  • A single-page app component calls _satellite.track in its mount lifecycle, which can run before a head-loaded async script has finished on the very first render.
  • The library file itself never loads at all - wrong environment in the embed code, a 404 on the library URL, or the request blocked by an ad blocker or a Content Security Policy. This looks identical in the console but the object never appears, even after the page is fully idle.

Fix it

1. Rule out the third case first. Open the Network tab, filter for the library filename Launch generates for your property, and confirm it returns 200. If it's missing, blocked, or 404s, fix the embed code or the CSP/ad-blocker issue before touching call-site timing - none of the steps below help a library that never loads.

2. Prefer the data layer over calling _satellite directly. Push the event to a data layer object and let a Launch rule's trigger (Core extension's Data Element Change, Window Loaded, or a custom event listener) fire the tracking - this removes the race entirely, since the rule only evaluates once Launch itself is running.

Application code (React/Vue/vanilla) - push, don't call
window.digitalData = window.digitalData || [];
window.digitalData.push({
  event: 'formSubmitted',
  formName: 'contact'
});

Wire a Launch rule with a "Custom Event" or Core "Direct Call" trigger listening for that push, and let the rule call _satellite internally from Launch's own code - never from your application bundle.

3. If you must call _satellite directly (SPA component, third-party integration), guard and queue it. Never assume it exists; check for it, and if it isn't there yet, retry briefly instead of failing silently or throwing.

Guarded direct call with short retry
function trackWhenReady(eventName, data, attemptsLeft = 20) {
  if (typeof window._satellite !== 'undefined' && typeof window._satellite.track === 'function') {
    window._satellite.track(eventName, data);
    return;
  }
  if (attemptsLeft <= 0) return; // library never loaded - see step 1
  setTimeout(() => trackWhenReady(eventName, data, attemptsLeft - 1), 100);
}

trackWhenReady('formSubmitted', { formName: 'contact' });

4. For pages where the very first interaction needs tracking (a hero CTA click before the page has fully settled), consider loading the Launch embed code without async/defer so it blocks briefly and finishes earlier - a real page-speed trade-off, so apply it only where the timing genuinely matters, not as a default.

How to verify it worked

  • Open the Adobe Experience Platform Debugger on the page. If it lists your Tags/Launch property and library build, the library loaded; if the property panel is empty, go back to step 1.
  • Trigger the action that used to throw the error, then check the browser console - no reference error means the call resolved against a real object.
  • In the Debugger's log/events view, confirm the rule fired (or the direct call registered) and inspect the resulting request in the Network tab, filtered to your analytics or Edge Network domain, to confirm a beacon actually left the browser with the expected variables.

Illustrative, not a measured result: a team whose SPA fired its first product-page event on component mount might see the error disappear entirely once that mount handler switches from a direct _satellite.track call to a data-layer push read by a Launch rule.

Webclat is not affiliated with Adobe Inc.