PHPackages                             stevecreekmore/cookies - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Authentication &amp; Authorization](/categories/authentication)
4. /
5. stevecreekmore/cookies

ActiveLibrary[Authentication &amp; Authorization](/categories/authentication)

stevecreekmore/cookies
======================

A Laravel package for managing cookie consent and GDPR compliance

v1.3.1(2mo ago)0201↓90.9%[1 PRs](https://github.com/stevecreekmore/cookies/pulls)MITBladePHP ^8.4CI passing

Since Jan 1Pushed 2mo agoCompare

[ Source](https://github.com/stevecreekmore/cookies)[ Packagist](https://packagist.org/packages/stevecreekmore/cookies)[ Docs](https://github.com/stevecreekmore/cookies)[ RSS](/packages/stevecreekmore-cookies/feed)WikiDiscussions main Synced 3w ago

READMEChangelog (3)Dependencies (14)Versions (6)Used By (0)

Laravel Cookie Consent
======================

[](#laravel-cookie-consent)

[![Latest Version on Packagist](https://camo.githubusercontent.com/f38e38c2cef8982a2af21c05238534e9ba71777baa31a54525a22aebbee98e99/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f762f7374657665637265656b6d6f72652f636f6f6b6965732e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/stevecreekmore/cookies)[![Tests](https://camo.githubusercontent.com/8ea477c2def8582cf5559f4d3e22970af6f3c59fff8e18607f39f32deed4de10/68747470733a2f2f696d672e736869656c64732e696f2f6769746875622f616374696f6e732f776f726b666c6f772f7374617475732f7374657665637265656b6d6f72652f636f6f6b6965732f72756e2d74657374732e796d6c3f6272616e63683d6d61696e266c6162656c3d7465737473267374796c653d666c61742d737175617265)](https://github.com/stevecreekmore/cookies/actions/workflows/run-tests.yml)[![Total Downloads](https://camo.githubusercontent.com/a2167c8d63d025efcaa087b748c0b9df427113b71743162e88392b4d90b156e2/68747470733a2f2f696d672e736869656c64732e696f2f7061636b61676973742f64742f7374657665637265656b6d6f72652f636f6f6b6965732e7376673f7374796c653d666c61742d737175617265)](https://packagist.org/packages/stevecreekmore/cookies)

A **GDPR-compliant** Laravel package for managing cookie consent with category-based consent management, script blocking, consent logging, and easy withdrawal.

Features
--------

[](#features)

- ✅ **GDPR Compliant** - Meets all major GDPR requirements
- 🚫 **Script Blocking** - Prevents non-consented scripts from loading
- 📝 **Consent Logging** - Database audit trail of all consent actions
- 🔄 **Easy Withdrawal** - Users can change their mind anytime
- 📊 **Detailed Cookie Information** - Show specific cookies, purposes, and durations
- 🎨 **Fully Customizable** - Themes, positioning, and text
- 🔌 **Blade Directives** - Easy integration with existing code
- 🌐 **Event System** - React to consent changes in JavaScript
- 📱 **Responsive Design** - Works on all devices

GDPR Compliance
---------------

[](#gdpr-compliance)

This package helps you comply with GDPR by:

1. **Blocking Non-Essential Cookies** - Scripts are blocked until consent is given
2. **Granular Consent** - Users can choose specific cookie categories
3. **Detailed Information** - Shows cookie names, purposes, durations, and providers
4. **Easy Withdrawal** - Floating button to change preferences anytime
5. **Consent Logging** - Audit trail stored in database (proof of consent)
6. **Privacy Policy Links** - Direct links to your policies
7. **Opt-in by Default** - No pre-checked boxes (except necessary cookies)

Installation
------------

[](#installation)

Install the package via composer:

```
composer require stevecreekmore/cookies
```

The package will automatically register its service provider.

### Publish Configuration

[](#publish-configuration)

Publish the configuration file:

```
php artisan vendor:publish --tag=cookies-config
```

### Publish Migrations (for consent logging)

[](#publish-migrations-for-consent-logging)

```
php artisan vendor:publish --tag=cookies-migrations
php artisan migrate
```

### Publish Views (Optional)

[](#publish-views-optional)

If you want to customize the banner appearance:

```
php artisan vendor:publish --tag=cookies-views
```

### Add Middleware

[](#add-middleware)

Add the middleware to your `bootstrap/app.php` (Laravel 11+):

```
->withMiddleware(function (Middleware $middleware) {
    $middleware->web(append: [
        \Stevecreekmore\Cookies\Middleware\AppendCookieConsentToResponse::class,
    ]);
})
```

Or for Laravel 10 and below, add to `app/Http/Kernel.php`:

```
protected $middlewareGroups = [
    'web' => [
        // ...
        \Stevecreekmore\Cookies\Middleware\AppendCookieConsentToResponse::class,
    ],
];
```

Configuration
-------------

[](#configuration)

### Define Your Cookies

[](#define-your-cookies)

Edit `config/cookies.php` to define the specific cookies your site uses:

```
'categories' => [
    'necessary' => [
        'enabled' => true,
        'required' => true,
        'label' => 'Necessary',
        'description' => 'These cookies are essential for the website to function properly.',
        'cookies' => [
            'session' => [
                'name' => 'laravel_session',
                'purpose' => 'Maintains user session state',
                'duration' => '2 hours',
                'provider' => 'This website',
            ],
            'csrf' => [
                'name' => 'XSRF-TOKEN',
                'purpose' => 'Security token to prevent cross-site request forgery',
                'duration' => '2 hours',
                'provider' => 'This website',
            ],
        ],
    ],
    'analytics' => [
        'enabled' => true,
        'required' => false,
        'label' => 'Analytics',
        'description' => 'These cookies help us understand how visitors interact with our website.',
        'cookies' => [
            'google_analytics' => [
                'name' => '_ga, _gid, _gat',
                'purpose' => 'Used to distinguish users and sessions for analytics',
                'duration' => '2 years (_ga), 24 hours (_gid)',
                'provider' => 'Google LLC',
            ],
        ],
    ],
    // Add more categories...
],
```

### Set Policy URLs

[](#set-policy-urls)

```
'policy_url' => env('COOKIE_PRIVACY_POLICY_URL', '/privacy-policy'),
'cookie_policy_url' => env('COOKIE_POLICY_URL', '/cookie-policy'),
```

Or in your `.env`:

```
COOKIE_CONSENT_ENABLED=true
COOKIE_CONSENT_LOG=true
COOKIE_PRIVACY_POLICY_URL=/privacy-policy
COOKIE_POLICY_URL=/cookie-policy
```

Usage
-----

[](#usage)

### Blocking Scripts Until Consent

[](#blocking-scripts-until-consent)

The most important GDPR feature - scripts won't load until the user consents:

#### Method 1: Blade Directive (Recommended)

[](#method-1-blade-directive-recommended)

```
@cookieConsentScript('analytics')
    // Google Analytics
    (function(i,s,o,g,r,a,m){i['GoogleAnalyticsObject']=r;i[r]=i[r]||function(){
    (i[r].q=i[r].q||[]).push(arguments)},i[r].l=1*new Date();a=s.createElement(o),
    m=s.getElementsByTagName(o)[0];a.async=1;a.src=g;m.parentNode.insertBefore(a,m)
    })(window,document,'script','https://www.google-analytics.com/analytics.js','ga');

    ga('create', 'UA-XXXXX-Y', 'auto');
    ga('send', 'pageview');
@endCookieConsentScript
```

#### Method 2: Manual Script Blocking

[](#method-2-manual-script-blocking)

```

    // Facebook Pixel code
    !function(f,b,e,v,n,t,s){/* ... */}

```

The script will automatically be activated once the user consents to that category.

### Checking Consent in PHP

[](#checking-consent-in-php)

```
use Stevecreekmore\Cookies\Facades\Cookies;

// Check specific category
if (Cookies::hasConsent('analytics')) {
    // Load analytics
}

// Get all consented categories
$categories = Cookies::getConsent();
// Returns: ['necessary', 'analytics']

// Check if any consent given
if (Cookies::hasGivenConsent()) {
    // User has interacted with banner
}

// Check if all categories accepted
if (Cookies::hasAcceptedAll()) {
    // User clicked "Accept All"
}
```

### Blade Conditional Directive

[](#blade-conditional-directive)

```
@cookieConsent('marketing')

@endcookieConsent

@cookieConsent('analytics')

@endcookieConsent
```

### JavaScript Event Listener

[](#javascript-event-listener)

React to consent changes in your JavaScript:

```
window.addEventListener('cookieConsentChanged', function(event) {
    const { categories, action, id } = event.detail;

    console.log('Consent action:', action); // 'accept_all', 'reject_all', or 'custom'
    console.log('Consented categories:', categories);
    console.log('Consent ID:', id);

    // Load scripts dynamically
    if (categories.includes('analytics')) {
        initializeAnalytics();
    }

    if (categories.includes('marketing')) {
        initializeMarketing();
    }
});
```

GDPR Compliance Features
------------------------

[](#gdpr-compliance-features)

### 1. Consent Logging (Audit Trail)

[](#1-consent-logging-audit-trail)

All consent actions are logged to the database:

```
use Stevecreekmore\Cookies\Models\CookieConsentLog;

// Get consent history for a user
$history = CookieConsentLog::where('cookie_id', $consentId)
    ->latest()
    ->get();

// Each log contains:
// - cookie_id (unique user identifier)
// - consented_categories (JSON array)
// - ip_address
// - user_agent
// - action (accept_all, reject_all, custom, withdraw)
// - timestamp
```

### 2. Consent Withdrawal

[](#2-consent-withdrawal)

A floating button appears after consent is given, allowing users to:

- Change their preferences
- Withdraw consent completely
- View what they previously accepted

This is a GDPR requirement - withdrawal must be as easy as giving consent.

### 3. Detailed Cookie Information

[](#3-detailed-cookie-information)

Users can click "View Cookie Details" to see a table with:

- Cookie names
- Purpose of each cookie
- Duration/expiry
- Provider (first-party or third-party)

### 4. Log Retention

[](#4-log-retention)

Control how long consent logs are kept (GDPR requires keeping records):

```
'log_retention_days' => 1095, // 3 years (default)
```

Clean up old logs:

```
use Stevecreekmore\Cookies\Models\CookieConsentLog;

// Manually clean up
CookieConsentLog::cleanupOldLogs();
```

Or schedule it in `app/Console/Kernel.php`:

```
protected function schedule(Schedule $schedule)
{
    $schedule->call(function () {
        \Stevecreekmore\Cookies\Models\CookieConsentLog::cleanupOldLogs();
    })->weekly();
}
```

Customization
-------------

[](#customization)

### Styling

[](#styling)

Customize appearance in `config/cookies.php`:

```
'styling' => [
    'position' => 'bottom', // bottom, top, center
    'theme' => 'dark', // light, dark
],
```

### Custom Text

[](#custom-text)

Change all text and labels:

```
'text' => [
    'title' => 'We Value Your Privacy',
    'description' => 'Your custom description...',
    'accept_all' => 'Accept All',
    'reject_all' => 'Only Essential',
    // ... more text options
],
```

### Custom Banner View

[](#custom-banner-view)

After publishing views, edit `resources/views/vendor/cookies/banner.blade.php` for complete control.

### Disable Consent Logging

[](#disable-consent-logging)

If you don't need database logging:

```
COOKIE_CONSENT_LOG=false
```

### Hide Settings Button

[](#hide-settings-button)

```
'show_settings_button' => false,
```

Testing
-------

[](#testing)

This package comes with a comprehensive test suite using Pest.

### Running Tests

[](#running-tests)

```
# Run all tests
composer test

# Run tests with coverage
composer test-coverage

# Run specific test file
vendor/bin/pest tests/Feature/CookieConsentTest.php

# Run tests with detailed output
vendor/bin/pest --verbose
```

### Test Coverage

[](#test-coverage)

The package includes 80+ test cases covering:

- **CookieConsent Class** - All consent checking methods
- **ConsentLogger Service** - Database logging functionality
- **Middleware** - Banner injection and HTML response handling
- **CookieConsentLog Model** - Database operations and cleanup
- **ConsentController** - API endpoint validation
- **Blade Directives** - Template rendering and conditional display
- **Facade** - All facade methods
- **Architecture** - Code quality and security standards

### Requirements for Testing

[](#requirements-for-testing)

The test suite requires:

- PHP ^8.4
- Laravel ^12.0
- SQLite (for in-memory testing)

All dependencies are automatically installed via `composer install`.

Best Practices for GDPR Compliance
----------------------------------

[](#best-practices-for-gdpr-compliance)

1. **Document All Cookies** - Fill in the `cookies` array for each category with specific cookie details
2. **Update Your Privacy Policy** - Include information about cookie usage
3. **Block All Non-Essential Scripts** - Use the Blade directive or manual blocking
4. **Keep Consent Logs** - Enable database logging for proof of consent
5. **Regular Audits** - Review what cookies your site actually sets
6. **Honor Withdrawals** - The floating button makes this easy
7. **Third-Party Cookies** - List all third-party providers clearly

API Reference
-------------

[](#api-reference)

### Facade Methods

[](#facade-methods)

```
Cookies::hasConsent(string $category): bool
Cookies::getConsent(): array
Cookies::hasGivenConsent(): bool
Cookies::hasAcceptedAll(): bool
Cookies::getEnabledCategories(): array
Cookies::getRequiredCategories(): array
```

### Blade Directives

[](#blade-directives)

```
@cookieConsentScript('category')
    // Your script here
@endCookieConsentScript

@cookieConsent('category')

@endcookieConsent
```

### JavaScript Events

[](#javascript-events)

```
// Consent changed
window.addEventListener('cookieConsentChanged', function(event) {
    // event.detail contains: { categories, action, id }
});
```

Troubleshooting
---------------

[](#troubleshooting)

### Scripts Not Loading After Consent

[](#scripts-not-loading-after-consent)

Make sure you're using `type="text/plain"` and the `data-cookie-consent` attribute:

```

    // Your script

```

### Banner Not Showing

[](#banner-not-showing)

1. Check middleware is added to web routes
2. Ensure `COOKIE_CONSENT_ENABLED=true` in `.env`
3. Check if consent cookie already exists (delete it to test)

### Consent Not Being Logged

[](#consent-not-being-logged)

1. Run migrations: `php artisan migrate`
2. Check `COOKIE_CONSENT_LOG=true` in config
3. Ensure CSRF token is present on the page: ``

Changelog
---------

[](#changelog)

Please see [CHANGELOG](CHANGELOG.md) for more information on what has changed recently.

Contributing
------------

[](#contributing)

Please see [CONTRIBUTING](https://github.com/stevecreekmore/.github/blob/main/CONTRIBUTING.md) for details.

Security Vulnerabilities
------------------------

[](#security-vulnerabilities)

Please review [our security policy](../../security/policy) on how to report security vulnerabilities.

Credits
-------

[](#credits)

- [Steven Creekmore](https://github.com/stevecreekmore)
- [All Contributors](../../contributors)

License
-------

[](#license)

The MIT License (MIT). Please see [License File](LICENSE.md) for more information.

###  Health Score

44

—

FairBetter than 91% of packages

Maintenance86

Actively maintained with recent releases

Popularity14

Limited adoption so far

Community9

Small or concentrated contributor base

Maturity56

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 75% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Every ~27 days

Total

4

Last Release

89d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/afb173c89698b330f558b86206eccb9b82ceba31d762eaef7da62880f07c77e8?d=identicon)[Creekmore108](/maintainers/Creekmore108)

---

Top Contributors

[![stevecreekmore](https://avatars.githubusercontent.com/u/5994720?v=4)](https://github.com/stevecreekmore "stevecreekmore (6 commits)")[![dependabot[bot]](https://avatars.githubusercontent.com/in/29110?v=4)](https://github.com/dependabot[bot] "dependabot[bot] (1 commits)")[![github-actions[bot]](https://avatars.githubusercontent.com/in/15368?v=4)](https://github.com/github-actions[bot] "github-actions[bot] (1 commits)")

---

Tags

laravelcookiesgdprprivacycookie-consentstevecreekmore

###  Code Quality

TestsPest

Code StyleLaravel Pint

### Embed Badge

![Health badge](/badges/stevecreekmore-cookies/health.svg)

```
[![Health](https://phpackages.com/badges/stevecreekmore-cookies/health.svg)](https://phpackages.com/packages/stevecreekmore-cookies)
```

###  Alternatives

[psalm/plugin-laravel

Psalm plugin for Laravel

3345.1M337](/packages/psalm-plugin-laravel)[laravel/horizon

Dashboard and code-driven configuration for Laravel queues.

4.1k91.3M279](/packages/laravel-horizon)[illuminate/database

The Illuminate Database package.

2.8k54.1M11.1k](/packages/illuminate-database)[laravel/ai

The official AI SDK for Laravel.

9782.1M161](/packages/laravel-ai)[moonshine/moonshine

Laravel administration panel

1.3k239.9k75](/packages/moonshine-moonshine)[illuminate/auth

The Illuminate Auth package.

9327.9M1.2k](/packages/illuminate-auth)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
