
Security News
CVE Volume Surges Past 48,000 in 2025 as WordPress Plugin Ecosystem Drives Growth
CVE disclosures hit a record 48,185 in 2025, driven largely by vulnerabilities in third-party WordPress plugins.
@consentry/next
Advanced tools
Next.js + React integration layer for the Consentry SDK. Manages cookie preferences, script injection, and analytics sync.
Next.js integration for Consentry consent management. React hooks, providers, and automatic script injection — works seamlessly with @consentry/ui for a complete solution.
useConsentManager() for easy state access@consentry/uinpm install @consentry/next @consentry/ui @consentry/core
npm install @consentry/next @consentry/core
👑 This is the recommended approach — using @consentry/next with @consentry/ui gives you a complete, plug-and-play consent management solution.
Create providers/consent-provider.tsx:
"use client";
import { ConsentConfig, ConsentManagerProvider } from "@consentry/next";
import ConsentManager from "@consentry/ui";
const ConsentProvider = ({ children }: { children: React.ReactNode }) => {
const consentConfig: ConsentConfig = {
debug: process.env.NODE_ENV === "development",
defaults: {
functional: true,
performance: false,
advertising: false,
social: false,
},
scripts: [
{
id: "gtag-js",
category: "performance",
consentRequired: true,
strategy: "afterInteractive",
src: "https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXXXX",
vendor: "Google Analytics",
},
{
id: "gtag-init",
category: "performance",
consentRequired: true,
strategy: "afterInteractive",
content: `
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-XXXXXXXXXX');
gtag('consent', 'default', {
analytics_storage: 'denied',
ad_storage: 'denied',
ad_user_data: 'denied',
ad_personalization: 'denied'
});
`,
vendor: "Google Analytics",
},
],
};
return (
<ConsentManagerProvider config={consentConfig}>
<ConsentManager mode="modal" dark={false} />
{children}
</ConsentManagerProvider>
);
};
export default ConsentProvider;
App Router (app/layout.tsx):
import ConsentProvider from "@/providers/consent-provider";
import "./globals.css";
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="en">
<body>
<ConsentProvider>{children}</ConsentProvider>
</body>
</html>
);
}
Pages Router (pages/_app.tsx):
import ConsentProvider from "@/providers/consent-provider";
import type { AppProps } from "next/app";
export default function App({ Component, pageProps }: AppProps) {
return (
<ConsentProvider>
<Component {...pageProps} />
</ConsentProvider>
);
}
"use client";
import { useConsentManager } from "@consentry/next";
export default function PrivacySettings() {
const { preferences, updatePreferences, hasConsentedOnce } = useConsentManager();
if (!hasConsentedOnce) {
return <p>Please accept or decline cookies first.</p>;
}
return (
<div>
<h2>Your Privacy Settings</h2>
<label>
<input
type="checkbox"
checked={preferences.performance}
onChange={e => updatePreferences({ ...preferences, performance: e.target.checked })}
/>
Analytics & Performance
</label>
<label>
<input
type="checkbox"
checked={preferences.advertising}
onChange={e => updatePreferences({ ...preferences, advertising: e.target.checked })}
/>
Advertising & Marketing
</label>
</div>
);
}
That's it! You now have a complete consent management system with banner, modal, and programmatic control.
The main provider that manages all consent state and script injection.
interface ConsentManagerProviderProps {
config: ConsentConfig; // Your consent configuration
children: React.ReactNode; // Your app content
storageKey?: string; // Custom localStorage key (default: 'consentry-preferences')
debug?: boolean; // Enable debug logging
}
Access consent state and controls from any component.
const {
preferences, // Current user preferences
updatePreferences, // Update all preferences
setCategoryConsent, // Update single category
hasConsentedTo, // Check specific category
hasConsentedOnce, // Has user made any choice?
acceptAll, // Accept all categories
rejectAll, // Reject all (except functional)
resetConsent, // Clear all consent data
} = useConsentManager();
interface ConsentConfig {
debug?: boolean; // Enable debug logging
defaults: CookiePreferences; // Default consent state
scripts: ConsentScript[]; // Scripts to manage
storageKey?: string; // Custom storage key
googleAnalyticsId?: string; // GA4 tracking ID for auto-setup
}
interface CookiePreferences {
functional: boolean; // Always true (required for site function)
performance: boolean; // Analytics, monitoring, A/B testing
advertising: boolean; // Marketing pixels, retargeting
social: boolean; // Social media embeds, sharing
}
interface ConsentScript {
id: string; // Unique identifier
category: ConsentCategory; // Which consent category
consentRequired?: boolean; // Require explicit consent
strategy?: "afterInteractive" | "lazyOnload" | "beforeInteractive";
src?: string; // External script URL
content?: string; // Inline script content
noscript?: string; // Fallback for no-JS
vendor?: string; // Third-party service name
default?: boolean; // Load by default
}
interface ConsentManagerHook {
preferences: CookiePreferences;
updatePreferences: (preferences: CookiePreferences) => void;
setCategoryConsent: (category: ConsentCategory, granted: boolean) => void;
hasConsentedTo: (category: ConsentCategory) => boolean;
hasConsentedOnce: () => boolean;
acceptAll: () => void;
rejectAll: () => void;
resetConsent: () => void;
}
const gaConfig: ConsentScript[] = [
{
id: "gtag-js",
category: "performance",
consentRequired: true,
strategy: "afterInteractive",
src: "https://www.googletagmanager.com/gtag/js?id=G-XXXXXXXXXX",
vendor: "Google Analytics",
},
{
id: "gtag-init",
category: "performance",
consentRequired: true,
strategy: "afterInteractive",
content: `
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-XXXXXXXXXX', {
send_page_view: true,
cookie_flags: 'SameSite=None;Secure'
});
// Required for Google Analytics v2 consent mode - must start with 'denied'
gtag('consent', 'default', {
analytics_storage: 'denied',
ad_storage: 'denied',
ad_user_data: 'denied',
ad_personalization: 'denied'
});
`,
vendor: "Google Analytics",
},
];
const facebookPixel: ConsentScript = {
id: "facebook-pixel",
category: "advertising",
consentRequired: true,
strategy: "afterInteractive",
content: `
!function(f,b,e,v,n,t,s)
{if(f.fbq)return;n=f.fbq=function(){n.callMethod?
n.callMethod.apply(n,arguments):n.queue.push(arguments)};
if(!f._fbq)f._fbq=n;n.push=n;n.loaded=!0;n.version='2.0';
n.queue=[];t=b.createElement(e);t.async=!0;
t.src=v;s=b.getElementsByTagName(e)[0];
s.parentNode.insertBefore(t,s)}(window, document,'script',
'https://connect.facebook.net/en_US/fbevents.js');
fbq('init', 'YOUR_PIXEL_ID');
fbq('track', 'PageView');
`,
noscript: `<img height="1" width="1" style="display:none" src="https://www.facebook.com/tr?id=YOUR_PIXEL_ID&ev=PageView&noscript=1" />`,
vendor: "Meta",
};
const consentConfig: ConsentConfig = {
debug: process.env.NODE_ENV === "development",
defaults: {
functional: true,
performance: false,
advertising: false,
social: false,
},
scripts: [
// Google Analytics
...gaConfig,
// Hotjar
{
id: "hotjar",
category: "performance",
consentRequired: true,
strategy: "afterInteractive",
content: `
(function(h,o,t,j,a,r){
h.hj=h.hj||function(){(h.hj.q=h.hj.q||[]).push(arguments)};
h._hjSettings={hjid:YOUR_HOTJAR_ID,hjsv:6};
a=o.getElementsByTagName('head')[0];
r=o.createElement('script');r.async=1;
r.src=t+h._hjSettings.hjid+j+h._hjSettings.hjsv;
a.appendChild(r);
})(window,document,'https://static.hotjar.com/c/hotjar-','.js?sv=');
`,
vendor: "Hotjar",
},
// Facebook Pixel
facebookPixel,
// Twitter Pixel
{
id: "twitter-pixel",
category: "advertising",
consentRequired: true,
strategy: "afterInteractive",
content: `
!function(e,t,n,s,u,a){e.twq||(s=e.twq=function(){s.exe?s.exe.apply(s,arguments):s.queue.push(arguments);
},s.version='1.1',s.queue=[],u=t.createElement(n),u.async=!0,u.src='https://static.ads-twitter.com/uwt.js',
a=t.getElementsByTagName(n)[0],a.parentNode.insertBefore(u,a))}(window,document,'script');
twq('init','YOUR_TWITTER_PIXEL_ID');
twq('track','PageView');
`,
vendor: "Twitter",
},
],
};
"use client";
import { useConsentManager } from "@consentry/next";
import { openConsentSettings } from "@consentry/ui";
export default function Footer() {
const { hasConsentedOnce, acceptAll, rejectAll } = useConsentManager();
return (
<footer>
<div>
<button onClick={() => openConsentSettings()}>Cookie Settings</button>
{!hasConsentedOnce && (
<div>
<button onClick={acceptAll}>Accept All Cookies</button>
<button onClick={rejectAll}>Reject All</button>
</div>
)}
</div>
</footer>
);
}
"use client";
import { useConsentManager } from "@consentry/next";
export default function AnalyticsDashboard() {
const { hasConsentedTo } = useConsentManager();
if (!hasConsentedTo("performance")) {
return (
<div>
<p>Analytics data requires performance cookies.</p>
<button onClick={() => openConsentSettings()}>Enable Analytics</button>
</div>
);
}
return <div>{/* Your analytics dashboard */}</div>;
}
"use client";
import { useConsentManager } from "@consentry/next";
export default function YouTubeEmbed({ videoId }: { videoId: string }) {
const { hasConsentedTo, setCategoryConsent } = useConsentManager();
if (!hasConsentedTo("social")) {
return (
<div className="consent-placeholder">
<p>This content requires social media cookies.</p>
<button onClick={() => setCategoryConsent("social", true)}>Enable Social Media</button>
</div>
);
}
return (
<iframe
src={`https://www.youtube.com/embed/${videoId}`}
width="560"
height="315"
frameBorder="0"
allowFullScreen
/>
);
}
import { useConsentManager } from "@consentry/next";
import { useCallback } from "react";
export function useAnalytics() {
const { hasConsentedTo, setCategoryConsent } = useConsentManager();
const trackEvent = useCallback(
(event: string, data?: any) => {
if (hasConsentedTo("performance") && typeof gtag !== "undefined") {
gtag("event", event, data);
}
},
[hasConsentedTo]
);
const enableAnalytics = useCallback(() => {
setCategoryConsent("performance", true);
}, [setCategoryConsent]);
return {
trackEvent,
enableAnalytics,
analyticsEnabled: hasConsentedTo("performance"),
};
}
// Usage
function MyComponent() {
const { trackEvent, analyticsEnabled } = useAnalytics();
const handleClick = () => {
trackEvent("button_click", { button_id: "header_cta" });
};
return <button onClick={handleClick}>Click me {analyticsEnabled && "(tracked)"}</button>;
}
const getConsentConfig = (): ConsentConfig => {
const isProd = process.env.NODE_ENV === "production";
return {
debug: !isProd,
defaults: {
functional: true,
performance: isProd, // Auto-enable in production
advertising: false,
social: false,
},
scripts: isProd ? productionScripts : developmentScripts,
};
};
<ConsentManagerProvider config={consentConfig} storageKey="my-app-consent">
{children}
</ConsentManagerProvider>
"use client";
import dynamic from "next/dynamic";
// Avoid hydration issues
const ConsentManager = dynamic(() => import("@consentry/ui"), {
ssr: false,
});
const ConsentProvider = ({ children }: { children: React.ReactNode }) => {
return (
<ConsentManagerProvider config={consentConfig}>
<ConsentManager mode="modal" />
{children}
</ConsentManagerProvider>
);
};
// __mocks__/@consentry/next.ts
export const useConsentManager = () => ({
preferences: {
functional: true,
performance: true,
advertising: false,
social: false,
},
updatePreferences: jest.fn(),
setCategoryConsent: jest.fn(),
hasConsentedTo: jest.fn(() => true),
hasConsentedOnce: jest.fn(() => true),
acceptAll: jest.fn(),
rejectAll: jest.fn(),
resetConsent: jest.fn(),
});
import { render, screen } from "@testing-library/react";
import { useConsentManager } from "@consentry/next";
import MyComponent from "./MyComponent";
jest.mock("@consentry/next");
test("shows analytics when performance cookies enabled", () => {
(useConsentManager as jest.Mock).mockReturnValue({
hasConsentedTo: (category: string) => category === "performance",
});
render(<MyComponent />);
expect(screen.getByText("Analytics Dashboard")).toBeInTheDocument();
});
The provider automatically handles Google's consent mode v2:
// Automatically called when preferences change
gtag("consent", "update", {
analytics_storage: preferences.performance ? "granted" : "denied",
ad_storage: preferences.advertising ? "granted" : "denied",
ad_user_data: preferences.advertising ? "granted" : "denied",
ad_personalization: preferences.advertising ? "granted" : "denied",
});
// ❌ Wrong - causes hydration issues
export default function Layout({ children }) {
return (
<ConsentManagerProvider config={config}>
<ConsentManager />
{children}
</ConsentManagerProvider>
);
}
// ✅ Correct - use dynamic import
const ConsentManager = dynamic(() => import("@consentry/ui"), { ssr: false });
// ❌ Wrong - bypasses consent management
<Script src="https://analytics.example.com/script.js" />;
// ✅ Correct - managed by consent system
scripts: [
{
id: "analytics",
category: "performance",
src: "https://analytics.example.com/script.js",
},
];
// ❌ Wrong - hook used outside provider
function App() {
const { preferences } = useConsentManager(); // Error!
return <div>...</div>;
}
// ✅ Correct - hook used inside provider
function App() {
return (
<ConsentManagerProvider config={config}>
<MyComponent />
</ConsentManagerProvider>
);
}
function MyComponent() {
const { preferences } = useConsentManager(); // Works!
return <div>...</div>;
}
@consentry/core — Framework-agnostic consent logic@consentry/ui — React components for banners and modalsFor the full experience with UI components, check out the @consentry/ui documentation which includes:
MIT — Copyright © 2025 Mustafa ONAL
FAQs
Next.js + React integration layer for the Consentry SDK. Manages cookie preferences, script injection, and analytics sync.
The npm package @consentry/next receives a total of 22 weekly downloads. As such, @consentry/next popularity was classified as not popular.
We found that @consentry/next demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 1 open source maintainer collaborating on the project.
Did you know?

Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.

Security News
CVE disclosures hit a record 48,185 in 2025, driven largely by vulnerabilities in third-party WordPress plugins.

Security News
Socket CEO Feross Aboukhadijeh joins Insecure Agents to discuss CVE remediation and why supply chain attacks require a different security approach.

Security News
Tailwind Labs laid off 75% of its engineering team after revenue dropped 80%, as LLMs redirect traffic away from documentation where developers discover paid products.