# Install on any HTML site > Add the TerraGaming Media site tag once and place ad units with one div each. This works on any site where you can edit the HTML: hand-written pages, static site generators, Webflow, Squarespace, Wix, Shopify themes and server templates. The portal shows your exact code under **Ad Units & Tags → Install site tag**. ## 1. Add the site tag once Paste the site tag into the `` of **every page**: your theme or layout template, so it is on each page exactly once. ```html ``` - `tgmads.example.com` is **your own** host, the CNAME you verified in Integration Setup. The tag loads your property's settings from it, so there is nothing else to configure. - Until your CNAME is verified, the tag loads from the shared host and carries your ids: ```html ``` One site tag serves every ad unit on the page. **Never add it again for a new unit**, and never copy `tag.js` into your own site: it must load from the host above. ## 2. Place your ad units Put a placement wherever an ad should appear. Use the ad unit ids from the portal: ```html
``` - The same unit can appear on many pages, and more than once on a page. - The **floating banner** unit anchors to the bottom of the screen wherever its div sits. Place it once, for example at the end of your layout. - **In-article ads** need no markup. The tag inserts them after the 3rd paragraph of the element matching your article selector (`.post-content` unless you change it in the portal), at most three per page. - An empty slot collapses (`data-tgm-state="unfilled"`), so your layout never shows a blank box. ## 3. Check it Open a page, then in the browser console run: ```js window.tgm.status(); ``` It shows your `propertyId`, `state: "running"` and every placement under `slots`. Within about 10 minutes the portal shows **Tag detected** for the property. Ads only appear once the visitor has consented to advertising (see [Content Security Policy and consent](../content-security-policy/)). ## Older installs Sites installed before October 2026 have an inline `window.tgmConfig = {…}` block and a `tgmQ.push(…)` script per unit. They keep working. To pick up portal changes such as a new article selector automatically, replace them with the site tag and placements above. --- # Install on WordPress > The TerraGaming Media Ads plugin adds the site tag, a block, a widget and a shortcode. :::caution[Not published yet] The TerraGaming Media Ads plugin is not published yet. Until it is, install the site tag and placements as on any HTML site (see [Install on any HTML site](../html/)): it works the same on every platform, including single-page apps. ::: ## 1. Install the plugin In WordPress, open **Plugins → Add New**, search for **TerraGaming Media Ads**, then **Install** and **Activate**. ## 2. Paste your site tag in the plugin settings Open **Settings → TerraGaming Media** and paste the site tag the portal shows under **Ad Units & Tags → Install site tag**. Then **Save**. The plugin adds it to the `` of every page: ```html ``` You can also fill in the fields under **Advanced** (host, property and publisher ids) instead. ## 3. Place your ad units Use any of these, with the ad unit ids from the portal: - **Block:** add the **TerraGaming Media Ad** block in the editor and enter the unit id. - **Widget:** add the **TerraGaming Media Ad** widget to a sidebar (Appearance → Widgets). - **Shortcode:** anywhere shortcodes work: ```text [tgm_ad unit="TGM-ABC-HRS01"] ``` **In-article ads are automatic.** The plugin marks the post content, so the tag can find your paragraphs on any theme. Turn it off under Settings → TerraGaming Media if you prefer your own article selector. ## Caching and optimisation plugins The plugin excludes the tag from WP Rocket's delay-JavaScript, LiteSpeed Cache, Autoptimize and SiteGround Optimizer. If you use another optimiser, exclude `tag.js` from combining, deferring and delaying. ## Without the plugin Paste the site tag into your theme's header (or with a header/footer plugin). Then place each unit with a **Custom HTML** block or widget containing `
`. See [Install on any HTML site](../html/). ## Check it On a post, run `window.tgm.status()` in the browser console. Within about 10 minutes the portal shows **Tag detected**. --- # Install on Laravel > The terragamingmedia/laravel-ads package adds Blade components for the site tag and ad units. ## 1. Install the package ```bash composer require terragamingmedia/laravel-ads ``` The service provider is discovered automatically. To publish the config file: ```bash php artisan vendor:publish --tag=tgm-config ``` ## 2. Add your values to `.env` ```bash TGM_HOST=tgmads.example.com ``` Once your CNAME is verified, the host is all you need. Before that, use the shared host and your ids: ```bash TGM_HOST=cdn.terramedia-sandbox.com TGM_PROPERTY=PROP-… TGM_PUBLISHER=PUB-… TGM_IN_ARTICLE_UNIT=TGM-…-INART TGM_ARTICLE_SELECTOR=".post-content" ``` `TGM_ENABLED=false` turns the tag off, for example on local environments. ## 3. Add the site tag to your layout In the `` of your main layout: ```blade ``` or `@tgmSiteTag`. With a Content Security Policy, the component adds the nonce from `Vite::cspNonce()` (or spatie/laravel-csp) automatically. You can also pass `nonce="…"`. ## 4. Place your ad units In any Blade view: ```blade ``` or `@tgmAd('TGM-ABC-HRS01')`. The same unit can appear more than once per page. In-article ads are automatic. ## Inertia, Livewire, Turbo - **Inertia (React or Vue):** keep `` in `app.blade.php` and place units with the React or Vue package (``). See [React](../react/) and [Vue](../vue/). - **Livewire `wire:navigate` and Turbo** update the URL with `pushState`. The tag starts a new page view by itself. Wrap the floating unit in `@persist('tgm-floating')` so it survives navigation. --- # Install on React, Next.js, TanStack Start and Remix > The @terragamingmedia/ads-react package loads the tag once and renders hydration-safe ad units. ## 1. Install the package ```bash npm install @terragamingmedia/ads-react ``` ## 2. Load the tag in your root layout `` renders the site tag. It works in server-rendered and client-only apps. Route changes are detected automatically. **Next.js (App Router)**, `app/layout.tsx`: ```tsx import { TgmScript } from "@terragamingmedia/ads-react"; export default function RootLayout({ children }: { children: React.ReactNode }) { return ( {children} ); } ``` - **Next.js (Pages Router):** put `` in the `` of `pages/_document.tsx`. - **TanStack Start / React Router v7 / Remix:** put it in the root route's ``, next to `` or ``. - **Vite / Create React App (no SSR):** wrap your app in ``, which loads the tag on mount. Before your CNAME is verified, also pass your ids: ```tsx ``` With a Content Security Policy, pass `nonce={nonce}`. In Next.js, read it from the request headers your middleware sets. ## 3. Place your ad units ```tsx import { TgmAd, TgmFloating } from "@terragamingmedia/ads-react"; ``` `` reserves space on the server and mounts the ad container only in the browser, so hydration never sees the tag's iframes. When it unmounts, the tag removes its ad. In-article ads are automatic. Use `articleSelector` (or a `data-tgm-article` attribute on your article element) to point the tag at your content. ## Routing Nothing to wire. The tag starts a new page view after each client-side navigation. If your loaders make the new page render more than about a second after the URL changes, switch to manual mode and call the hook from your router: ```tsx ; // in a component that re-renders on navigation: import { useTgmPageview } from "@terragamingmedia/ads-react"; useTgmPageview(pathname); ``` Do not use `next/script` with `strategy="worker"` (Partytown): the tag needs the page's DOM. --- # Install on Vue and Nuxt > The @terragamingmedia/ads-vue package has a Nuxt module, a Vue plugin and a TgmAd component. ## 1. Install the package ```bash npm install @terragamingmedia/ads-vue ``` ## 2a. Nuxt: add the module ```ts // nuxt.config.ts export default defineNuxtConfig({ modules: ["@terragamingmedia/ads-vue/nuxt"], tgm: { host: "tgmads.example.com" }, }); ``` The module adds the site tag to every page's `` and registers `` and ``. You can also set the host with `NUXT_PUBLIC_TGM_HOST`. ## 2b. Vue: install the plugin ```ts import { createApp } from "vue"; import { createTgm } from "@terragamingmedia/ads-vue"; createApp(App) .use(createTgm({ host: "tgmads.example.com" })) .mount("#app"); ``` Before your CNAME is verified, also pass your ids: `{ host: "cdn.terramedia-sandbox.com", property: "PROP-…", publisher: "PUB-…", inArticle: "TGM-…-INART", articleSelector: ".post-content" }`. ## 3. Place your ad units ```vue ``` `` reserves space during server rendering and mounts the ad container in the browser only. When it unmounts, the tag removes its ad. In-article ads are automatic. ## Routing Vue Router and Nuxt navigation are detected automatically. To call page views yourself, set `spa: "manual"` and call `useTgm().pageview()` in `router.afterEach`. --- # Install on Angular, Svelte and other frameworks > Load the tag with @terragamingmedia/ads and render placements in the browser. Any framework can use the site tag and `
` placements directly (see [Install on any HTML site](../html/)). The tag detects route changes and placements mounted later. The `@terragamingmedia/ads` package adds a typed, SSR-safe loader: ```bash npm install @terragamingmedia/ads ``` ```ts import { loadTag } from "@terragamingmedia/ads"; // In the browser only, once (repeated calls return the same tag): const tgm = await loadTag({ host: "tgmads.example.com" }); tgm?.on("render", ({ targetId }) => console.log("ad in", targetId)); ``` `loadTag` returns `null` during server rendering. Render placements only in the browser, so hydration never sees the tag's iframes. ## Angular ```ts // app.component.ts constructor() { afterNextRender(() => void loadTag({ host: "tgmads.example.com" })); } ``` ```html
``` ## Svelte and SvelteKit ```svelte {#if browser}
{/if} ``` ## Astro Put the site tag in your base layout's `` and the `
` placements in your pages. With view transitions, the tag starts a new page view on each navigation. --- # Serve through Google Ad Manager > Run TerraGaming Media units as GAM custom HTML creatives (SafeFrame off). If your ad slots are managed in Google Ad Manager (GAM), each TerraGaming Media unit runs as a **custom HTML creative**. ## 1. One creative per unit In GAM, create a **Third-party** (custom HTML) creative for each placement, and **turn off “Serve into a SafeFrame”**. The tag cannot run inside a SafeFrame and stays off there. ## 2. Creative code Each creative carries its own loader, because a creative runs in its own frame. This is the only case where a unit includes `tag.js`: ```html
``` Before your CNAME is verified, the loader carries your ids: ``. The portal's **Get Tags → Google Ad Manager** tab shows each unit's creative code. ## Notes - The page itself needs no site tag for GAM-only placements. In-article ads need the site tag on the page. - Consent: the creative reads your consent manager from the page (friendly iframe), the same as on the page. --- # Single-page apps and client-side routing > How the tag follows route changes, late placements and unmounts, and when to use manual mode. The tag handles client-side navigation by itself (`spa: "auto"`, the default). ## What counts as a new page - `history.pushState` or back/forward to another **path or query** starts a new page view. The tag waits for the new route to render: once your page's DOM has changed, until it has been quiet for 250 ms. If nothing changes within a second, it assumes the route rendered before the URL changed. It never waits more than 3 seconds. - `history.replaceState` (infinite scroll, UTM clean-up) and hash-only changes **never** start a page view, so ads on screen stay. - A new page view removes the previous page's ads, finds your article again and decides every placement on the new page. The floating banner stays unless you set `floating: "per-pageview"`. ## Placements mounted later A `
` added after load (a component mounting, "load more") is decided automatically in the current page view. When it is removed, its ad is removed too. Units that were not filled are tried again on the next page view. ## Manual mode If your router renders the new page more than about a second after the URL changes (slow loaders), or you want exact control, set manual mode and tell the tag when the new page is ready: ```html ``` (or `spa: "manual"` in `window.tgmConfig`, or the `spa` option of the packages), then: ```js // after each navigation has rendered: window.tgm?.pageview(); ``` Calling `tgm.pageview()` yourself also switches the tag to manual mode. A call right after the tag's own page view for the same URL is merged into it, so you never count a page twice. ## The API | Call | Does | | --------------------- | ----------------------------------------------------------------------------------------------------------- | | `tgm.pageview()` | Starts a new page view (manual mode). | | `tgm.refresh(["id"])` | Decides the given placements again in this page view. | | `tgm.destroy()` | Removes every ad and stops the tag. Loading `tag.js` again starts a fresh one. | | `tgm.on(event, cb)` | `render`, `unfilled`, `viewable`, `close`, `decide`, `pageview`, `remove`. Returns an unsubscribe function. | | `tgm.status()` | Configuration, state and every slot, for checking an install. | --- # Content Security Policy and consent > The CSP directives the tag needs, and how it follows your visitors' privacy choices. ## Content Security Policy If your site sends a `Content-Security-Policy` header, allow your tag host (`tgmads.example.com`, or `cdn.terramedia-sandbox.com` before your CNAME is verified): ```text script-src https://tgmads.example.com; connect-src https://tgmads.example.com; frame-src https://tgmads.example.com; ``` The one-line site tag needs **no** `'unsafe-inline'`. With a nonce-based policy, add the nonce to the ` ``` That one line is the whole site tag once your CNAME is verified. The tag reads your property's settings from your own host, including the article selector you set in the portal. Before verification it also carries your ids as `data-tgm-*` attributes. Add it **once**: it serves every ad unit on the page, so you never add it again for a new unit. The site tag also runs in-article placements automatically, using the in-article ad unit created with your property. Single-page apps (React, Next.js, Vue, Nuxt…) need nothing extra: the tag follows route changes by itself. There are step-by-step guides for [HTML](../install/html/), [WordPress](../install/wordpress/), [Laravel](../install/laravel/), [React / Next.js](../install/react/), [Vue / Nuxt](../install/vue/) and [Google Ad Manager](../install/google-ad-manager/). The Install dialog also copies ready-made instructions for an [AI assistant](../install/ai-assistant/). ### 3. Place ad units Add each ad unit's placement where the ad should appear, for example `
` (see _Creating Ad Units and Placing Tags_). ### 4. Check it The Install dialog shows **Tag detected** within about 10 minutes of the first visit. In the browser console, `window.tgm.status()` shows your property and every placement on the page. ### Consent and privacy The tag honours Global Privacy Control and your consent platform: when a visitor declines advertising, no TerraGaming Media cookie is set. --- # Creating Ad Units and Placing Tags > Create ad units for each placement and drop their placements into your pages, apps or Google Ad Manager. An **ad unit** is one placement on your site with a fixed size. Each has an ID such as `TGM-SPN-MOB01` that you will see in your reports. ### Creating an ad unit Open **Ad Units & Tags**, select **Create New Ad Unit**, choose the property and the slot size — **300x250**, **728x90**, or the **floating banner**, which anchors to the bottom of the screen — and name it after where it appears. Then copy its placement from **Get Tags** on the unit's row. Tags become available once the property is approved and live on our network. ### Placing an ad unit A placement is markup only. It never includes the tag, because the **site tag** is added once per site (see _Installing the Site Tag and Your CNAME_): ```html
``` - **HTML**: paste the placement where the ad should render. The same unit can appear on many pages, and more than once on a page. - **WordPress**: use the TerraGaming Media Ad block, widget or the `[tgm_ad unit="…"]` shortcode from our plugin, or a Custom HTML block. - **Apps and frameworks**: the React, Vue and Laravel packages render it as `` or ``. - **Google Ad Manager**: add the GAM snippet from **Get Tags → Google Ad Manager** as a custom (third-party) HTML creative with **Serve into a SafeFrame** turned off. SafeFrame delivery is not supported. This is the only placement that carries its own loader, because a creative runs in its own frame. ### Checking delivery **Revenue Reports** breaks impressions and earnings down by ad unit. --- # Blocking Advertisers and Ad Categories > Control which advertisers and kinds of ads appear on your sites. You decide which ads appear on your properties. Changes take effect across our network within minutes. ### Advertiser Blocklist Under **Advertiser Blocklist**, search for an advertiser and block them on all your properties or only on selected ones. Blocked advertisers' campaigns are never served on those sites. You can remove a block at any time. ### Category Filters Under **Category Filters**, switch off whole categories of ads (Sportsbook; Slots & Video Poker; Table Games & Live Dealer; Bingo & Lottery; Poker & Cardroom) for all your properties at once, or override the network-wide setting for a single property. Multi-tab interactive banners are not affected by these filters. ### Who can change them Owners, Admins and Standard members can edit blocklists and category filters; Read Only members can't. --- # Setting Up Payouts and Tax Information > Get paid by bank transfer or stablecoins, and understand payout timing and your 1099. Set up how you are paid under **Payout Settings**. Only organization Owners and Admins can see earnings and payouts. ### Payout methods - **Direct Deposit (ACH / Wire)** — connect your bank through Stripe Connect. You are redirected to Stripe to verify your business and tax details and link your account. - **Cryptocurrency** — USDC or USDT on Ethereum (ERC-20), or USDC on Solana. Network fees are deducted from the payout, and funds sent to a wrong address cannot be recovered, so double-check it. U.S. publishers must complete Stripe onboarding (including tax details) before any payout, even when paid in crypto. ### When you are paid Earnings for a month are paid on the **1st of the month after next** — once the advertisers have been charged. For example, January's earnings are paid on March 1. The minimum payout is **$100**; smaller balances roll over to the next payout. Every payout has a statement under **Payment History**. ### Tax documents U.S. publishers receive a **1099-NEC** each year by the end of January in the **Tax Documents** center; we email you when it is ready. International publishers are exempt. TerraGaming Media does not provide tax advice. --- # Managing Publisher Users & Roles > Invite your team and choose what each member can see and change. Give your team access to your publisher workspace with the right permission tier. ### Permission tiers - **Admin** — full control: users, payout settings and tax documents. The primary administrator is always an Admin. - **Standard** — manage properties, ad tags, category filters and blocklists. No payouts or user management. - **Read Only** — view revenue reports, audience insights and payment history. ### Inviting a user Open **Manage Organization**, select **Invite User**, enter their email and choose a tier. They receive a one-time invitation link, valid for seven days. You can resend or revoke pending invitations. ### Notifications Each member chooses their own email notifications under **Notification Preferences** — website approval status, payment method changes, tax documents, payouts and network announcements. Security emails are always sent. ### Account security Turn on two-factor authentication under **Account Security**, where you can also review and sign out of your active sessions.