How a variable works
A variable is a named placeholder that Tag Manager fills in at the moment it is needed. Rather than typing the same value into every tag, you refer to the variable, and the container resolves it freshly on each event — so one reference returns the current page path on this page and a different one on the next.
They come in two families. Built-in variables are ready-made values such as the page URL, the referrer or the text of a clicked element; you switch them on rather than build them. User-defined variables are the ones you create: a value read from the data layer, a fixed constant, a lookup table that maps one input to several outputs, a cookie reader, or custom JavaScript when nothing else fits.
The point that confuses people first is that variables serve two masters. The same object can supply the value a tag sends and provide the condition a trigger tests, which is why a broken variable often breaks firing and reporting at the same time.
Why variables matter
They are what makes one tag do the work of many. A single purchase tag can report every order because the order value, currency and transaction reference all arrive as variables. A lookup table can route one form tag to the right destination for each form on the site. Without variables, tracking is a pile of near-identical tags that all have to be edited whenever anything changes.
They are also where personal data escapes. A variable that reads an email address out of a URL or a form field will hand it to whichever platform the tag reports to. That breaches advertising platform policy and privacy law in most of the markets my clients sell into, and it is done accidentally far more often than deliberately.
Where variables go wrong
Empty values are the everyday fault. If a variable reads a key that has not been written yet, it returns nothing, the tag still fires, and the destination records a blank. Preview shows a fired tag, so the problem hides until someone questions a report.
Scraping is the fragile one. Custom JavaScript that digs a price out of the page by class name works beautifully until a designer renames the class, and then it fails silently rather than loudly.
Data types cause the rest. A price captured with a currency symbol or thousands separators arrives as text, and platforms that expect a number will treat it as no value at all. Values also persist: once written into the data layer, a value stays available for the rest of that page view unless it is deliberately cleared, so a later tag can send the last product viewed rather than the current one.
How to act on it
Prefer values the website pushes on purpose over anything the container has to scrape. Ask the developer for a small, documented set of values on the pages that matter, and build variables against those.
Name each variable so its purpose and source are obvious, set a default such as “not set” so blanks show up in reports instead of vanishing, and never store an email, phone number or full name in one unless you are using a platform feature built for it. In preview, open the variables list at the moment the tag fires and read the actual values — the fired tick tells you nothing about what was inside.