The TikTok Pixel is a snippet of JavaScript that reports website actions back to TikTok for ad measurement and optimization (TikTok Ads Manager Help), and the LinkedIn Insight Tag is the equivalent for LinkedIn — a lightweight JavaScript tag that enables conversion tracking and retargeting (LinkedIn Help). On a Next.js App Router site the clean approach is the same for both: load each tag once with next/script using strategy="afterInteractive", then fire a pageview yourself on client-side route changes. Next.js is a single-page application after the first load, so the base tag never reloads on in-app navigation, and without a manual pageview those navigations go uncounted.
Load the TikTok Pixel with next/script
The TikTok base code defines a global ttq object and loads the SDK asynchronously. The afterInteractive strategy tells Next.js to inject the script after the page becomes interactive rather than blocking hydration, which is the recommended placement for analytics tags (Next.js docs). Put the Pixel ID in an environment variable so staging and production stay distinct.
// app/_analytics/TikTokBase.tsx
"use client";
import Script from "next/script";
export function TikTokBase() {
return (
<Script id="tiktok-pixel" strategy="afterInteractive">{`
!function(w,d,t){w.TiktokAnalyticsObject=t;var ttq=w[t]=w[t]||[];
ttq.methods=["page","track","identify","instances","load"];
ttq.setAndDefer=function(o,m){o[m]=function(){o.push([m].concat([].slice.call(arguments,0)))}};
for(var i=0;i<ttq.methods.length;i++)ttq.setAndDefer(ttq,ttq.methods[i]);
ttq.load=function(e){var u="https://analytics.tiktok.com/i18n/pixel/events.js";
ttq._i=ttq._i||{};ttq._i[e]=[];var s=d.createElement("script");
s.async=!0;s.src=u+"?sdkid="+e;var f=d.getElementsByTagName("script")[0];
f.parentNode.insertBefore(s,f)};
ttq.load("${process.env.NEXT_PUBLIC_TIKTOK_PIXEL_ID}");
`}</Script>
);
}
This snippet is a condensed form of TikTok's official base code; treat the canonical version in your Events Manager install screen as the source of truth and keep the method list in sync.
Track standard events on TikTok
Standard events are the named actions TikTok recognizes for optimization and reporting — ViewContent, AddToCart, CompletePayment, CompleteRegistration and others (TikTok standard events reference). Fire them when the matching action happens, attaching a value and currency for revenue events so TikTok can attribute spend correctly.
// after a successful checkout
window.ttq?.track("CompletePayment", {
value: 49.0,
currency: "USD",
contents: [{ content_id: "pro-plan", content_type: "product" }],
});
Sending the canonical event name matters: a custom string like "purchase_done" won't drive TikTok's payment-optimization models the way CompletePayment does. The same holds for the event properties — TikTok expects value and currency on payment events, and a contents array describing what was bought, so its reporting and value-based bidding have something to work with.
Install the LinkedIn Insight Tag
The LinkedIn Insight Tag is keyed to a numeric Partner ID from your LinkedIn Campaign Manager account, which you push onto a _linkedin_partner_id global before loading the tag's loader script (LinkedIn Help). Again, load it with next/script and afterInteractive.
// app/_analytics/LinkedInBase.tsx
"use client";
import Script from "next/script";
const PID = process.env.NEXT_PUBLIC_LINKEDIN_PARTNER_ID;
export function LinkedInBase() {
return (
<Script id="linkedin-insight" strategy="afterInteractive">{`
window._linkedin_partner_id="${PID}";
window._linkedin_data_partner_ids=window._linkedin_data_partner_ids||[];
window._linkedin_data_partner_ids.push("${PID}");
(function(l){if(!l){window.lintrk=function(a,b){window.lintrk.q.push([a,b])};
window.lintrk.q=[]}var s=document.getElementsByTagName("script")[0];
var b=document.createElement("script");b.type="text/javascript";b.async=true;
b.src="https://snap.licdn.com/li.lms-analytics/insight.min.js";
s.parentNode.insertBefore(b,s);})(window.lintrk);
`}</Script>
);
}
LinkedIn conversions are usually defined in Campaign Manager and triggered by a URL or an event, but you can also fire a conversion in code with window.lintrk("track", { conversion_id: <id> }) when an action completes (LinkedIn conversion tracking help). Use the numeric conversion ID that Campaign Manager assigns.
The App Router gotcha: pageviews on route change
Both base tags record one pageview when they load. After that, Next.js handles navigation client-side, so the browser never reloads and neither tag fires again on its own. To recover those views, watch the route in a Client Component using usePathname and useSearchParams — both are hooks that read the current URL on the client (Next.js usePathname, useSearchParams) — and re-fire a pageview whenever the path or query changes.
// app/_analytics/PageviewTracker.tsx
"use client";
import { useEffect } from "react";
import { usePathname, useSearchParams } from "next/navigation";
export function PageviewTracker() {
const pathname = usePathname();
const search = useSearchParams();
useEffect(() => {
window.ttq?.page(); // TikTok pageview
window.lintrk?.("track"); // LinkedIn pageview
}, [pathname, search]);
return null;
}
Next.js requires any component reading useSearchParams to sit inside a <Suspense> boundary, or the whole route opts out of static rendering (Next.js useSearchParams). Wrap <PageviewTracker /> in <Suspense> in your root layout to keep the rest of the page statically rendered.
Load after consent, not before
In regions covered by consent law, the tags should not run until the visitor has agreed to advertising or analytics cookies. The simplest pattern is to render the base components conditionally — gate <TikTokBase /> and <LinkedInBase /> behind your consent state so the SDKs only load after a user opts in. TikTok exposes consent-mode parameters through the same Events Manager flow (TikTok Events Manager help), and deferring the script entirely until consent is the most defensible default. Because the tags are loaded by next/script rather than inlined in the document head, toggling them on after consent is a state change, not a redeploy.
Verify before you trust the numbers
Confirm each tag actually fires before reading any report. For TikTok, open Events Manager, find your Pixel, and use its testing view to watch Pageview and CompletePayment arrive as you click through the site (TikTok Events Manager help). For LinkedIn, Campaign Manager shows the Insight Tag's status — it reports as active once it has received traffic, and conversions appear under the conversion you defined (LinkedIn Insight Tag help). The official browser tag-assistant extensions for each platform are the fastest way to see the exact payloads leaving the page.
Why client tags alone undercount
Both the TikTok Pixel and the LinkedIn Insight Tag run in the browser, which means ad blockers, tracking-prevention features, and declined consent all strip events before they leave the page. That loss is structural, not a bug in your setup. The durable fix is to also record the same conversions as server-side, first-party owned events from your own backend — events that fire regardless of what the browser blocks — and reconcile the ad-platform numbers against that owned baseline. Get the client tags right for optimization and attribution, but keep your own count as the figure you actually defend in a board meeting.