Framework Integration
Copy-pasteable patterns for the script integration across the frameworks publishers actually use.
How the script tag behaves
When the page parses the <script>, our code reads its data-placement attribute and inserts a styled <div> at the script's position in the DOM. The div expands to fill its parent, so whatever wrapper you put the script in becomes the ad slot. One ad rendered per script load.
The patterns below all do the same thing in framework idiom: ensure the script runs after the wrapper is in the DOM, and re-run it on remount so the ad sticks around through navigation.
React (Client Component)
Inject the script in a useEffect and clean it up on unmount. This works in any React app: CRA, Vite, Remix client, Next.js client components.
"use client";
import { useEffect, useRef } from "react";
export function AdBanner({ placementId }: { placementId: string }) {
const ref = useRef<HTMLDivElement>(null);
useEffect(() => {
const script = document.createElement("script");
script.async = true;
script.src = "https://adventory.to/ad.banner.js";
script.id = "adventory-" + placementId;
script.dataset.placement = placementId;
ref.current?.appendChild(script);
return () => { script.remove(); };
}, [placementId]);
return <div ref={ref} />;
}Next.js (App Router)
In the App Router, prefer a Client Component using the React pattern above. A <script> rendered in a Server Component does run on first page load, but the inserted ad div lives in DOM that React replaces on every soft navigation, so the ad disappears as soon as the visitor clicks an internal link. A Client Component re-runs the injection on mount, which keeps the ad consistent across route changes.
Recommended: Client Component
// app/components/AdBanner.tsx
"use client";
import { useEffect, useRef } from "react";
export function AdBanner({ placementId }: { placementId: string }) {
const ref = useRef<HTMLDivElement>(null);
useEffect(() => {
const script = document.createElement("script");
script.async = true;
script.src = "https://adventory.to/ad.banner.js";
script.id = "adventory-" + placementId;
script.dataset.placement = placementId;
ref.current?.appendChild(script);
return () => { script.remove(); };
}, [placementId]);
return <div ref={ref} />;
}
// Use it from any Server Component:
// <AdBanner placementId="..." />Alternative: next/script
For pages that don't navigate (a static landing page), next/script with strategy="afterInteractive" works:
import Script from "next/script";
export default function Page() {
return (
<>
<div id="ad-slot" />
<Script
src="https://adventory.to/ad.banner.js"
data-placement="YOUR_PLACEMENT_ID"
id="adventory-YOUR_PLACEMENT_ID"
strategy="afterInteractive"
/>
</>
);
}Astro
Drop the script directly into your .astro markup. Astro doesn't hydrate plain HTML by default, so the script tag works as a static include and the inserted ad div is left alone.
---
// src/components/AdBanner.astro
const { placementId } = Astro.props;
---
<div>
<script
is:inline
async
src="https://adventory.to/ad.banner.js"
data-placement={placementId}
id={`adventory-${placementId}`}
></script>
</div>The is:inline directive tells Astro to render the tag as-is rather than processing it. Use the component anywhere: <AdBanner placementId="..." />.
SvelteKit
Use a +page.svelte with an onMount that injects the script. SvelteKit's client-side router replaces page content on navigation, so the mount/unmount lifecycle matches what you want.
<script lang="ts">
import { onMount } from "svelte";
export let placementId: string;
let container: HTMLDivElement;
onMount(() => {
const script = document.createElement("script");
script.async = true;
script.src = "https://adventory.to/ad.banner.js";
script.id = "adventory-" + placementId;
script.dataset.placement = placementId;
container.appendChild(script);
return () => script.remove();
});
</script>
<div bind:this={container}></div>Vue 3
Mount the script in onMounted and clean up in onUnmounted:
<script setup lang="ts">
import { onMounted, onUnmounted, ref } from "vue";
const props = defineProps<{ placementId: string }>();
const container = ref<HTMLDivElement | null>(null);
let script: HTMLScriptElement | null = null;
onMounted(() => {
script = document.createElement("script");
script.async = true;
script.src = "https://adventory.to/ad.banner.js";
script.id = "adventory-" + props.placementId;
script.dataset.placement = props.placementId;
container.value?.appendChild(script);
});
onUnmounted(() => {
script?.remove();
});
</script>
<template>
<div ref="container"></div>
</template>When the script fights your framework
Some setups (heavy SPA routers, frameworks that aggressively diff the DOM, strict CSP that blocks third-party scripts) make the snippet brittle. The escape hatch is the JSON API: fetch the ad as data, render it with your own components, fire the impression pixel yourself.