Muro
Troubleshooting

muro is not defined

Fix errors like "muro is not defined" or "Cannot read properties of undefined (reading 'track')" when sending custom events.

window.muro only exists once muro.js has loaded and run. If your code calls window.muro.track() before then, or on a page where the script can't run, you get an error like one of these:

  • ReferenceError: muro is not defined
  • TypeError: Cannot read properties of undefined (reading 'track')
  • Property 'muro' does not exist on type 'Window' (TypeScript)

Why it happens

  • The script hasn't run yet. muro.js loads with async, so it runs as soon as it's downloaded, which can be after your own code. Muro has no queue for calls made before it loads.
  • The script was blocked. Ad blockers, privacy extensions, some networks and a strict Content Security Policy can stop it from loading at all. window.muro then never exists for that visitor.
  • The tag has no data-project-id. Without a project ID the script stops straight away and doesn't create window.muro.
  • The code runs on the server. In Next.js, Astro and other frameworks with server rendering, code outside the browser has no window.

Fix it

Use optional chaining

Call track like this everywhere:

window.muro?.track('signup');

If Muro hasn't loaded, or never will for this visitor, the call is skipped quietly and your page keeps working. This is the recommended pattern.

Track clicks without JavaScript

For buttons and links, skip the JavaScript and add an attribute instead:

<button data-muro-event="signup">Sign up</button>

A click on the element, or anything inside it, sends a custom event named signup. It works for elements added later and across single-page-app navigations, and it can't throw. It doesn't send properties. See Track custom events.

Call track from the browser only

In React, Next.js and similar frameworks, call track from event handlers or effects, which only run in the browser:

'use client';

export function SignupButton() {
  return (
    <button onClick={() => window.muro?.track('signup')}>
      Sign up
    </button>
  );
}

Don't call it at the top level of a module or in a server component.

Add a TypeScript declaration

TypeScript doesn't know about window.muro until you declare it. Add this to a .d.ts file in your project, such as muro.d.ts:

export {};

declare global {
  interface Window {
    muro?: {
      track: (
        name: string,
        props?: Record<string, string | number | boolean>
      ) => void;
    };
  }
}

Marking muro as optional makes TypeScript remind you to use ?..

Events that must fire on page load

For an event you want to send as soon as a page opens, for example on a thank-you page, wait for the script to load:

function trackWhenReady(name, props) {
  if (window.muro) return window.muro.track(name, props);
  var tag = document.querySelector('script[src*="api.muroanalytics.com/muro.js"]');
  if (tag) tag.addEventListener('load', function () { window.muro?.track(name, props); });
}

trackWhenReady('purchase_complete');

If all you need is to count visits to a page, you don't need an event at all. Create a Page goal for its path instead. See Set up goals.

Verify it works

  1. Open your site with DevTools → Console open. Type window.muro and press Enter. You should see an object with a track function.
  2. Trigger your event. The Console shows no errors.
  3. In Network, filtered to collect, a request with "event_type":"custom" and your event name appears with status 202.
  4. The event appears in the dashboard's Custom Events panel.

Next steps

On this page