Ensuring GDPR compliance for your SaaS application means implementing category-based consent management, privacy-first design patterns, and server-side consent checking. From cookie consent banners to preference management and consent tracking, creating a production-ready GDPR compliance system requires weeks of careful development. Fastack comes with a complete, privacy-first cookie consent package that handles consent management, category-based preferences, and analytics integration—saving you weeks of development time.
Why GDPR compliance matters for SaaS
GDPR compliance is essential for SaaS applications operating in the EU:
- Legal requirement for EU operations
- User trust through transparent data handling
- Category-based consent for granular control
- Server-side consent checking for reliable enforcement
- Analytics integration that respects user preferences
What you get with Fastack
Fastack includes a complete GDPR-compliant cookie consent system:
Cookie consent provider
Fastack provides a React context provider that manages cookie consent state throughout your application:
'use client';
import { createContext, useContext, type ReactNode } from 'react';
import { useCookieConsent } from '../../hooks';
import type { CookieConsentState, CookieConsentActions } from '../../hooks';
interface CookieConsentContextValue extends CookieConsentState, CookieConsentActions {}
const CookieConsentContext = createContext<CookieConsentContextValue | undefined>(undefined);
interface CookieConsentProviderProps {
children: ReactNode;
}
export function CookieConsentProvider({ children }: CookieConsentProviderProps) {
const consentState = useCookieConsent();
return (
<CookieConsentContext.Provider value={consentState}>
{children}
</CookieConsentContext.Provider>
);
}
export function useCookieConsentContext(): CookieConsentContextValue {
const context = useContext(CookieConsentContext);
if (context === undefined) {
throw new Error('useCookieConsentContext must be used within a CookieConsentProvider');
}
return context;
}The CookieConsentProvider wraps your application and provides cookie consent state and actions to all child components. This allows you to access consent information and manage preferences from anywhere in your application, such as opening the consent modal via a "Manage Cookie Preferences" button.
Category-based consent
Fastack supports granular consent categories:
- Necessary - Always enabled, required for site functionality
- Functional - Enhanced functionality cookies
- Analytics - Analytics and tracking cookies
- Performance - Performance monitoring cookies
- Advertisement - Advertising and marketing cookies
Server-side consent checking
Fastack provides server-side utilities to check consent before initializing analytics or other tracking services:
import { ConsentCookies } from '@saas/cookies/utils';
import { cookies } from 'next/headers';
export async function GET() {
const cookieStore = await cookies();
if (!ConsentCookies.hasAnalyticsConsent(cookieStore)) {
// Don't track analytics
return Response.json({ tracked: false });
}
// Initialize analytics tracking
return Response.json({ tracked: true });
}The ConsentCookies.hasAnalyticsConsent() function checks server-side cookies to determine if the user has given analytics consent. This ensures that analytics and tracking services are only initialized when the user has given explicit consent, providing reliable GDPR compliance even before client-side JavaScript loads.
Consent management UI
Fastack includes pre-built UI components for cookie consent:
- Cookie banner - Initial consent request
- Consent modal - Detailed preference management
- Preference persistence - Stores consent in cookies
- Consent events - Dispatches events for analytics integration
'use client';
import { CookieConsentBanner } from './cookie-consent-banner';
import { CookieConsentModal } from './cookie-consent-modal';
import { useCookieConsentContext } from '../context/cookie-consent-context';
import type { CookieConsentLabels } from '../types/labels';
interface CookieConsentProps {
labels: CookieConsentLabels;
}
export function CookieConsent({ labels }: CookieConsentProps) {
const {
isOpen,
isCustomizeOpen,
preferences,
acceptAll,
rejectAll,
savePreferences,
openCustomize,
closeCustomize,
} = useCookieConsentContext();
return (
<>
{isOpen && (
<CookieConsentBanner
labels={labels}
onAcceptAll={acceptAll}
onRejectAll={rejectAll}
onCustomize={openCustomize}
/>
)}
<CookieConsentModal
isOpen={isCustomizeOpen}
onClose={closeCustomize}
onSave={savePreferences}
currentPreferences={preferences}
labels={labels}
/>
</>
);
}The CookieConsent component uses the useCookieConsentContext hook to access consent state and actions. It conditionally renders the banner when consent hasn't been given, and manages the modal for detailed preference customization.
'use client';
import { Button } from '@saas/ui-core';
import type { CookieConsentLabels } from '../types/labels';
interface CookieConsentBannerProps {
labels: CookieConsentLabels;
onAcceptAll: () => void;
onRejectAll: () => void;
onCustomize: () => void;
}
export function CookieConsentBanner({
labels,
onAcceptAll,
onRejectAll,
onCustomize,
}: CookieConsentBannerProps) {
return (
<div className="fixed bottom-0 left-0 right-0 z-50 p-4 md:p-6 bg-default-50 border-t border-divider shadow-lg">
<div className="max-w-7xl mx-auto">
<div className="flex flex-col md:flex-row md:items-center md:justify-between gap-4">
<div className="flex-1">
<h3 className="text-lg font-semibold mb-2">{labels.banner.title}</h3>
<p className="text-sm text-foreground/70 mb-4 md:mb-0">
{labels.banner.description}
</p>
</div>
<div className="flex flex-col sm:flex-row gap-3 md:ml-6">
<Button
variant="bordered"
size="sm"
onPress={onCustomize}
className="min-w-[120px]"
>
{labels.banner.customize}
</Button>
<Button
variant="bordered"
size="sm"
onPress={onRejectAll}
className="min-w-[120px]"
>
{labels.banner.rejectAll}
</Button>
<Button
color="primary"
size="sm"
onPress={onAcceptAll}
className="min-w-[120px]"
>
{labels.banner.acceptAll}
</Button>
</div>
</div>
</div>
</div>
);
}The CookieConsentBanner component displays a fixed banner at the bottom of the page with three action buttons: Customize (opens the modal), Reject All, and Accept All. The banner is responsive and uses HeroUI components for consistent styling.
'use client';
import { Modal, ModalContent, ModalHeader, ModalBody, ModalFooter, Button, Switch } from '@saas/ui-core';
import { useState, useEffect } from 'react';
import type { CookieConsentPreferences } from '../../utils';
import type { CookieConsentLabels } from '../types/labels';
interface CookieConsentModalProps {
isOpen: boolean;
onClose: () => void;
onSave: (preferences: Partial<CookieConsentPreferences>) => void;
currentPreferences: CookieConsentPreferences | null;
labels: CookieConsentLabels;
}
type CookieCategory = 'functional' | 'analytics' | 'performance' | 'advertisement';
export function CookieConsentModal({
isOpen,
onClose,
onSave,
currentPreferences,
labels,
}: CookieConsentModalProps) {
const [preferences, setPreferences] = useState<Partial<CookieConsentPreferences>>({
functional: currentPreferences?.functional ?? false,
analytics: currentPreferences?.analytics ?? false,
performance: currentPreferences?.performance ?? false,
advertisement: currentPreferences?.advertisement ?? false,
});
const handleToggle = (category: CookieCategory) => {
setPreferences((prev) => ({
...prev,
[category]: !prev[category],
}));
};
const handleSave = () => {
onSave(preferences);
};
return (
<Modal isOpen={isOpen} onClose={onClose} size="2xl" placement="center">
<ModalContent>
<ModalHeader>
<h2 className="text-2xl font-bold">{labels.modal.title}</h2>
</ModalHeader>
<ModalBody>
<p className="text-foreground/70">{labels.modal.description}</p>
{/* Necessary Cookies - Always Enabled */}
<div className="p-4 rounded-lg border border-divider bg-content1">
<div className="flex items-center justify-between">
<div className="flex-1 mr-6">
<h3 className="font-semibold mb-1">{labels.categories.necessary.title}</h3>
<p className="text-sm text-foreground/70">{labels.categories.necessary.description}</p>
</div>
<Switch isSelected={true} isDisabled size="sm" />
</div>
</div>
{/* Other Categories */}
{['functional', 'analytics', 'performance', 'advertisement'].map((category) => (
<div key={category} className="p-4 rounded-lg border border-divider">
<div className="flex items-center justify-between">
<div className="flex-1">
<h3 className="font-semibold mb-1">{labels.categories[category].title}</h3>
<p className="text-sm text-foreground/70">{labels.categories[category].description}</p>
</div>
<Switch
isSelected={preferences[category as CookieCategory] ?? false}
onValueChange={() => handleToggle(category as CookieCategory)}
size="sm"
/>
</div>
</div>
))}
</ModalBody>
<ModalFooter>
<Button variant="bordered" onPress={onClose}>
{labels.modal.cancel}
</Button>
<Button color="primary" onPress={handleSave}>
{labels.modal.save}
</Button>
</ModalFooter>
</ModalContent>
</Modal>
);
}The CookieConsentModal component provides a detailed interface for managing cookie preferences. It displays all cookie categories with toggle switches, with necessary cookies always enabled and disabled. Users can customize their preferences for functional, analytics, performance, and advertisement cookies before saving.
Content Security Policy (CSP) headers
Fastack includes built-in Content Security Policy (CSP) headers to protect against XSS attacks and data injection. The CSP is automatically configured based on your analytics and monitoring setup (Google Tag Manager, Google Analytics, and PostHog):
/**
* Generate Content Security Policy header
*/
export function generateCSPHeader(options?: {
allowGTM?: boolean;
allowGA?: boolean;
allowPostHog?: boolean;
postHogApiHost?: string;
postHogUiHost?: string;
allowGoogleFonts?: boolean;
allowInlineScripts?: boolean;
allowInlineStyles?: boolean;
allowUnsafeEval?: boolean;
additionalScriptSrc?: string[];
additionalStyleSrc?: string[];
additionalImgSrc?: string[];
additionalConnectSrc?: string[];
}): string {
const {
allowGTM = true,
allowGA = true,
allowPostHog = !!process.env.NEXT_PUBLIC_POSTHOG_KEY,
postHogApiHost = process.env.NEXT_PUBLIC_POSTHOG_API_HOST || 'https://us.i.posthog.com',
postHogUiHost = process.env.NEXT_PUBLIC_POSTHOG_UI_HOST,
allowGoogleFonts = true,
allowInlineScripts = true,
allowInlineStyles = true,
allowUnsafeEval = process.env.NODE_ENV === 'development',
additionalScriptSrc = [],
additionalStyleSrc = [],
additionalImgSrc = [],
additionalConnectSrc = [],
} = options || {};
// Build CSP directives with appropriate sources
const scriptSrc = [
"'self'",
...(allowInlineScripts ? ["'unsafe-inline'"] : []),
...(allowUnsafeEval ? ["'unsafe-eval'"] : []),
...(allowGTM || allowGA ? ['https://www.googletagmanager.com'] : []),
...(allowGA ? ['https://www.google-analytics.com'] : []),
...(allowPostHog ? ['https://*.i.posthog.com'] : []),
...additionalScriptSrc,
];
const styleSrc = [
"'self'",
...(allowInlineStyles ? ["'unsafe-inline'"] : []),
...(allowGoogleFonts ? ['https://fonts.googleapis.com'] : []),
...additionalStyleSrc,
];
// ... additional directives for fonts, images, connect, etc.
const directives = [
`default-src 'self'`,
`script-src ${scriptSrc.join(' ')}`,
`style-src ${styleSrc.join(' ')}`,
`img-src ${imgSrc.join(' ')}`,
`font-src ${fontSrc.join(' ')}`,
`connect-src ${connectSrc.join(' ')}`,
`frame-src ${frameSrc.join(' ')}`,
`worker-src 'self' blob:`,
`object-src 'none'`,
`base-uri 'self'`,
`form-action 'self'`,
`frame-ancestors 'self'`,
`upgrade-insecure-requests`,
];
return directives.join('; ');
}The generateCSPHeader function creates a comprehensive CSP policy that allows necessary resources while blocking potentially dangerous content. It automatically includes Google Tag Manager, Google Analytics, and PostHog sources if configured, and supports custom sources for additional services. In development mode, it also allows 'unsafe-eval' for Next.js Hot Module Replacement (HMR).
import { generateSecurityHeaders } from '@saas/utils';
export default async function middleware(req: NextRequest) {
// ... authentication and routing logic ...
// Set security headers including Content Security Policy
const securityHeaders = generateSecurityHeaders({
allowGTM: !!process.env.NEXT_PUBLIC_GOOGLE_TAG_MANAGER_ID,
allowGA: !!process.env.NEXT_PUBLIC_GA_MEASUREMENT_ID,
allowPostHog: !!process.env.NEXT_PUBLIC_POSTHOG_KEY,
postHogApiHost: process.env.NEXT_PUBLIC_POSTHOG_API_HOST,
postHogUiHost: process.env.NEXT_PUBLIC_POSTHOG_UI_HOST,
allowGoogleFonts: true,
allowInlineScripts: true,
allowInlineStyles: true,
});
Object.entries(securityHeaders).forEach(([key, value]) => {
response.headers.set(key, value);
});
return response;
}The middleware automatically sets CSP headers on all responses, configured based on your environment variables. This ensures that:
- XSS protection - Prevents cross-site scripting attacks
- Data injection prevention - Blocks unauthorized data sources
- Analytics integration - Automatically allows GTM, GA, and PostHog if configured
- Service worker support - Enables PWA functionality
- HTTPS enforcement - Upgrades insecure requests automatically
Fastack also sets additional security headers including X-Frame-Options, X-Content-Type-Options, X-XSS-Protection, Referrer-Policy, and Permissions-Policy for comprehensive security protection.
Time saved: 20+ hours
Building GDPR-compliant cookie consent from scratch typically requires:
- Implementing consent management system (4-6 hours)
- Creating category-based consent logic (3-4 hours)
- Building consent UI components (4-5 hours)
- Implementing server-side consent checking (2-3 hours)
- Integrating with analytics providers (2-3 hours)
- Configuring Content Security Policy headers (2-3 hours)
- Testing GDPR compliance (2-3 hours)
- Documenting consent system (1-2 hours)
Total: 20-29 hours of development time that you save with Fastack.
Best practices included
Fastack follows GDPR best practices:
- Privacy-first design - No tracking without explicit consent
- Category-based consent - Granular user control
- Server-side enforcement - Reliable consent checking
- Consent persistence - Remembers user preferences
- Analytics integration - Respects consent preferences
- Content Security Policy - Built-in CSP headers for XSS protection
Conclusion
GDPR compliance is essential for SaaS applications, and cookie consent management is a critical component. Fastack provides a complete, privacy-first cookie consent system that saves you weeks of development time while ensuring legal compliance and user trust.
With Fastack, you get:
- Cookie consent provider with React context for global state management
- Category-based consent for granular user control
- Server-side consent checking for reliable enforcement
- Pre-built UI components for consent management
- Analytics integration that respects user preferences
- Content Security Policy headers for XSS and data injection protection
- GDPR-compliant consent system built-in from day one
Ready to build your SaaS faster?
Get our scalable, production-ready boilerplate to save endless hours of development and setup
