Why doesn't the dataLayer show which script pushed an event?
Because the dataLayer is just an array, and an array records values, not callers. Typing dataLayer in the console shows you what was pushed and never by whom.
Sooner or later every tag manager setup grows a mystery event: a dataLayer.push() that nobody on the team remembers adding. Maybe it duplicates your purchase event, maybe it fires a page_view with the wrong parameters. Setting a conditional breakpoint on Array.prototype.push works, but it is slow, breaks on sites with monkey-patched dataLayers, and only catches pushes that happen while you sit there.
Event Watcher answers the "who" automatically. It hooks the dataLayer at document_start and classifies every push by analyzing the call stack at push time: website (first-party page code), tag-manager (GTM, Tealium, Adobe Launch, or another TMS in the stack), script (a third-party script), or historical (pushed before the hook was installed).
What do you need before you start?
Event Watcher installed and DevTools open on the Event Watcher panel before you reload the page. Classification happens live at push time, so anything pushed while the panel was closed can only ever be labelled historical.
No special profile is needed; a normal session is fine. The default Stream view is where you will start.
How do you find the script behind a dataLayer push, step by step?
Click the push in the stream and read its DataLayer Push Source section: it names the URL of the script that made the call and classifies the push as website, tag-manager, script, or historical. The six steps below cover the single-event answer and the two views that give you the same answer across a whole session.
- Reload the page and let the stream fill. dataLayer pushes (and Adobe Client Data Layer events, where a site uses that instead) appear alongside network events; use the search box to filter by the event name you are hunting (e.g.
purchase). - Every push row carries a small initiator badge: a house icon for Website, a tag icon for Tag Manager, a fork icon for Script. That badge alone often answers the question.
/images/screenshots/guides/dl-source-stream-badges.png
- Click the push to open its detail view. The DataLayer Push Source section shows the classification plus the URL of the script that made the call. For known platforms it renders a full badge with the platform's icon, name, and brand color, so "some script pushed this" becomes "the Hotjar snippet pushed this".
/images/screenshots/guides/dl-source-detail-push-source.png
- To audit all pushes by origin at once, switch to Grouped view: click the + chip next to the Tool and Page view buttons and pick the Datalayer pivot. Pushes group into Website / Tag Manager / Script / Historical, with the TMS vendor or the concrete script URL as the second tier. This is the fastest way to spot a vendor script polluting your dataLayer across the whole session.
/images/screenshots/guides/dl-source-grouped-pivot.png
- If the source is a script you don't recognize, switch to Script view. It shows the loading dependency tree: who loaded that script (the page, GTM, or another script), and what it loaded in turn, so you can trace the push back to the tag or snippet that introduced it.
- Turn on DL Nesting in the options bar to see the other direction too: which GTM tags fired because of the push, nested underneath it in the stream.
What does a healthy dataLayer look like, and what does a problem look like?
Healthy means every event name has exactly one source, and your business events come from your own page code. A problem looks like a third-party script authoring events you depend on, or the same event name arriving from two different origins.
Good: your core ecommerce and page events (page_view, add_to_cart, purchase) classify as Website, pushed by your own templates or data layer code. Pushes classified as Tag Manager are expected internals (GTM's own gtm.js, gtm.dom, gtm.load, or tags you deliberately configured to push). Each event name has exactly one source.
Bad: a business-critical event classified as Script: a third-party vendor is injecting events into your dataLayer, which can double-count conversions or overwrite your parameters. The same event name arriving from two different sources (a duplicate-firing setup). Or a pile of historical pushes for events you expected to capture live, which usually means the page pushed them from inline code before any script could run, worth knowing when you rely on push ordering. When the culprit is a tag inside GTM, use the container preview and swap guide to test the fix without publishing.