
Research
2025 Report: Destructive Malware in Open Source Packages
Destructive malware is rising across open source registries, using delays and kill switches to wipe code, break builds, and disrupt CI/CD.
@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.
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.

Research
Destructive malware is rising across open source registries, using delays and kill switches to wipe code, break builds, and disrupt CI/CD.

Security News
Socket CTO Ahmad Nassri shares practical AI coding techniques, tools, and team workflows, plus what still feels noisy and why shipping remains human-led.

Research
/Security News
A five-month operation turned 27 npm packages into durable hosting for browser-run lures that mimic document-sharing portals and Microsoft sign-in, targeting 25 organizations across manufacturing, industrial automation, plastics, and healthcare for credential theft.