├── LICENSE.md ├── README-v4.md ├── README.md ├── composer.json ├── config └── meta-pixel.php ├── phpstan-baseline.neon ├── phpstan.neon.dist ├── resources └── views │ ├── body.blade.php │ └── head.blade.php ├── src ├── Components │ ├── Body.php │ └── Head.php ├── EventLayer.php ├── Facades │ └── MetaPixel.php ├── FacebookPixelServiceProvider.php ├── MetaPixel.php └── MetaPixelMiddleware.php └── upgrade-v4-to-v5.md /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) combindma 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README-v4.md: -------------------------------------------------------------------------------- 1 | # Facebook Pixel integration for Laravel 2 | 3 | [![Latest Version on Packagist](https://img.shields.io/packagist/v/combindma/laravel-facebook-pixel.svg?style=flat-square)](https://packagist.org/packages/combindma/laravel-facebook-pixel) 4 | [![GitHub Tests Action Status](https://img.shields.io/github/actions/workflow/status/combindma/laravel-facebook-pixel/run-tests.yml?branch=main&label=tests&style=flat-square)](https://github.com/combindma/laravel-facebook-pixel/actions?query=workflow%3ATests+branch%3Amaster) 5 | [![GitHub Code Style Action Status](https://img.shields.io/github/actions/workflow/status/combindma/laravel-facebook-pixel/fix-php-code-style-issues.yml?branch=main&label=code%20style&style=flat-square)](https://github.com/combindma/laravel-facebook-pixel/actions?query=workflow%3A"Check+%26+fix+styling"+branch%3Amaster) 6 | [![Total Downloads](https://img.shields.io/packagist/dt/combindma/laravel-facebook-pixel.svg?style=flat-square)](https://packagist.org/packages/combindma/laravel-facebook-pixel) 7 | 8 | A Complete Facebook Pixel implementation for your Laravel application. 9 | 10 | ## Introduction 11 | 12 | This package provides a smooth integration of Meta Pixel, along with a straightforward implementation of the latest Conversions API, enhancing your overall experience. 13 | 14 | ## Pre-requisites 15 | 16 | ### Register a Meta Pixel 17 | 18 | To get started with the pixel Meta, you must have a Meta pixel registered: Read this guide. 19 | 20 | ### Conversions API 21 | 22 | If you plan to use Conversions API then you need to: 23 | 24 | #### Obtain An Access Token 25 | To use the Conversions API, you need to generate an access token, which will be passed as a parameter in every API call. 26 | 27 | Refer to 28 | 29 | Conversions API Guide to learn more. 30 | 31 | 32 | 33 | ## Installation 34 | 35 | You can install the package via composer: 36 | 37 | ```bash 38 | composer require combindma/laravel-facebook-pixel 39 | ``` 40 | 41 | You can publish the config file with: 42 | 43 | ```bash 44 | php artisan vendor:publish --tag="facebook-pixel-config" 45 | ``` 46 | 47 | This is the contents of the published config file: 48 | 49 | ```php 50 | return [ 51 | /* 52 | * The Facebook Pixel id, should be a code that looks something like "XXXXXXXXXXXXXXXX". 53 | */ 54 | 'facebook_pixel_id' => env('FACEBOOK_PIXEL_ID', ''), 55 | 56 | /* 57 | * The key under which data is saved to the session with flash. 58 | */ 59 | 'sessionKey' => env('FACEBOOK_PIXEL_SESSION_KEY', config('app.name').'_facebookPixel'), 60 | 61 | /* 62 | * To use the Conversions API, you need an access token. For Documentation please see: https://developers.facebook.com/docs/marketing-api/conversions-api/get-started 63 | */ 64 | 'token' => env('FACEBOOK_PIXEL_TOKEN', ''), //Only if you plan using Conversions API for server events 65 | 66 | /* 67 | * Enable or disable script rendering. Useful for local development. 68 | */ 69 | 'enabled' => env('FACEBOOK_PIXEL_ENABLED', false), 70 | 71 | /* 72 | * This is used to test server events 73 | */ 74 | 'test_event_code' => env('FACEBOOK_TEST_EVENT_CODE') 75 | ]; 76 | ``` 77 | 78 | If you plan on using the [flash-functionality](#flashing-data-for-the-next-request) you must install the FacebookPixelMiddleware, after the StartSession middleware: 79 | 80 | ```php 81 | // app/Http/Kernel.php 82 | protected $middleware = [ 83 | ... 84 | \Illuminate\Session\Middleware\StartSession::class, 85 | \Combindma\FacebookPixel\MetaPixelMiddleware::class, 86 | ... 87 | ]; 88 | ``` 89 | 90 | ## Usage - Meta Pixel 91 | 92 | ### Include scripts in Blade 93 | 94 | Insert head view after opening head tag, and body view after opening body tag 95 | 96 | ```html 97 | 98 | 99 | 100 | @include('facebookpixel::head') 101 | 102 | 103 | @include('facebookpixel::body') 104 | 105 | ``` 106 | 107 | Your events will also be rendered here. To add an event, use the `track()` function. 108 | 109 | ```php 110 | // CheckoutController.php 111 | use Combindma\FacebookPixel\Facades\MetaPixel; 112 | 113 | public function index() 114 | { 115 | MetaPixel::track('Purchase', ['currency' => 'USD', 'value' => 30.00]); 116 | return view('thank-you'); 117 | } 118 | ``` 119 | 120 | This renders: 121 | 122 | ```html 123 | 124 | 125 | 126 | 127 | 128 | 129 | 130 | 131 | 132 | ``` 133 | 134 | You can also specify a unique event ID for any of your events so that, if you plan using the conversions API you avoid duplications. 135 | 136 | ```php 137 | //For example your order id 138 | FacebookPixel::track('Purchase', ['currency' => 'USD', 'value' => 30.00], '123456'); 139 | ``` 140 | 141 | 142 | #### Flashing data for the next request 143 | 144 | The package can also set event to render on the next request. This is useful for setting data after an internal redirect. 145 | 146 | ```php 147 | // ContactController.php 148 | use Combindma\FacebookPixel\Facades\MetaPixel; 149 | 150 | public function postContact() 151 | { 152 | // Do contact form stuff... 153 | MetaPixel::flashEvent('Lead', [ 154 | 'content_name' => 'Auto Insurance', 155 | 'content_category' => 'Quote', 156 | 'value' => 400.00, 157 | 'currency' => 'USD' 158 | ]); 159 | return redirect()->action('ContactController@getContact'); 160 | } 161 | ``` 162 | 163 | After a form submit, the following event will be parsed on the contact page: 164 | 165 | ```html 166 | 167 | 168 | 169 | 170 | 171 | 172 | 182 | 183 | 184 | ``` 185 | 186 | ### Available Methods 187 | 188 | ```php 189 | use Combindma\FacebookPixel\Facades\MetaPixel; 190 | 191 | // Retrieve your Pixel id 192 | $id = MetaPixel::pixelId(); 193 | // Set Pixel id on the fly 194 | MetaPixel::setPixelId('XXXXXXXX'); 195 | // Set Pixel token on the fly 196 | MetaPixel::setToken('XXXXXXXX'); 197 | // Check whether script rendering is enabled 198 | $enabled = MetaPixel::isEnabled(); // true|false 199 | // Enable and disable script rendering on the fly 200 | MetaPixel::enable(); 201 | MetaPixel::disable(); 202 | // Add event to the event layer (automatically renders right before the pixel script). Setting new values merges them with the previous ones. 203 | MetaPixel::track('eventName', ['attribute' => 'value']); 204 | MetaPixel::track('eventName', ['attribute' => 'value'], 'event_id'); //with an event id 205 | MetaPixel::track('eventName'); //without properties 206 | MetaPixel::track('eventName', [], 'event_id'); //with an event id but without properties 207 | // Flash event for the next request. Setting new values merges them with the previous ones. 208 | MetaPixel::flashEvent('eventName', ['attribute' => 'value']); 209 | MetaPixel::flashEvent('eventName', ['attribute' => 'value'], 'event_id'); //with an event id 210 | MetaPixel::flashEvent('eventName'); //without properties 211 | //Clear the event layer. 212 | MetaPixel::clear(); 213 | ``` 214 | 215 | ### Custom Events 216 | 217 | You can also track a specific custom event on your website. This feature is not available for flashed events. 218 | 219 | ```php 220 | use Combindma\FacebookPixel\Facades\MetaPixel; 221 | 222 | // In your controller 223 | MetaPixel::trackCustom('CUSTOM-EVENT-NAME', ['custom_parameter' => 'ABC', 'value' => 10.00, 'currency' => 'USD']); 224 | //With an event ID 225 | MetaPixel::trackCustom('CUSTOM-EVENT-NAME', ['custom_parameter' => 'ABC', 'value' => 10.00, 'currency' => 'USD'], 'EVENT_ID'); 226 | ``` 227 | 228 | This renders: 229 | 230 | ```html 231 | 232 | 233 | 234 | 235 | 236 | 237 | 242 | 243 | 244 | ``` 245 | 246 | ### Advanced matching 247 | 248 | This package provides by default advanced matching. We retrieve the email and the user id from authenticated user and include it in the Pixel base code fbq('init') function call as a third parameter. 249 | 250 | ```html 251 | 252 | 253 | 261 | 262 | 263 | 264 | 265 | 266 | ``` 267 | 268 | ### Macroable 269 | 270 | Adding events to pages can become a repetitive process. Since this package isn't supposed to be opinionated on what your events should look like, the FacebookPixel is macroable. 271 | 272 | ```php 273 | use Combindma\FacebookPixel\Facades\MetaPixel; 274 | 275 | //include this in your macrobale file 276 | MetaPixel::macro('purchase', function ($product) { 277 | MetaPixel::track('Purchase', [ 278 | 'currency' => 'EUR', 279 | 'value' => $product->price 280 | ]); 281 | }); 282 | 283 | //in your controller 284 | MetaPixel::purchase($product); 285 | ``` 286 | 287 | 288 | ## Usage - Conversions API 289 | 290 | If you plan on using [Conversions API](https://developers.facebook.com/docs/marketing-api/conversions-api/get-started) functionalities. Yous should specify the token in your .env file first. 291 | 292 | For every request yous should specify a unique event id for handling Pixel Duplicate Events and Conversions API. 293 | 294 | This is how you can start: 295 | 296 | ```php 297 | use Combindma\FacebookPixel\Facades\MetaPixel; 298 | use FacebookAds\Object\ServerSide\Content; 299 | use FacebookAds\Object\ServerSide\CustomData; 300 | use FacebookAds\Object\ServerSide\DeliveryCategory; 301 | use FacebookAds\Object\ServerSide\UserData; 302 | 303 | //Prepare User Data first. 304 | // By default, the IP Address, User Agent and fbc/fbp cookies are added. 305 | $user_data = MetaPixel::userData()->setEmail('joe@eg.com')->setPhone('12345678901'); 306 | 307 | $content = (new Content()) 308 | ->setProductId('product123') 309 | ->setQuantity(1) 310 | ->setDeliveryCategory(DeliveryCategory::HOME_DELIVERY); 311 | 312 | $custom_data = (new CustomData()) 313 | ->setContents(array($content)) 314 | ->setCurrency('usd') 315 | ->setValue(123.45); 316 | 317 | $eventId = uniqid('prefix_'); 318 | 319 | //send request 320 | MetaPixel::send('Purchase', $eventId ,$custom_data, $user_data); 321 | ``` 322 | 323 | If you don't specify the $user_data parameter, by default we retrieve the email & the id from Auth::user() if the user is authenticated. 324 | We use the user id as a same external_id in Meta Pixel and conversions API 325 | 326 | ```php 327 | FacebookPixel::send('Purchase', $eventId, $custom_data); 328 | ``` 329 | 330 | If you want to test server events, you need to specify the FACEBOOK_TEST_EVENT_CODE in your .env file. By default, this test code will be sent in all API request. 331 | 332 | So Don't forget to delete after you finish your server tests. 333 | 334 | You can use the [Playload Helper](https://developers.facebook.com/docs/marketing-api/conversions-api/payload-helper) to learn more about the requests to send. 335 | 336 | ## Testing 337 | 338 | ```bash 339 | composer test 340 | ``` 341 | 342 | ## Contributing 343 | 344 | Please see [CONTRIBUTING](CONTRIBUTING.md) for details. 345 | 346 | ## Security Vulnerabilities 347 | 348 | Please review [our security policy](../../security/policy) on how to report security vulnerabilities. 349 | 350 | ## Credits 351 | 352 | - [Combind](https://github.com/Combindma) 353 | - [All Contributors](../../contributors) 354 | 355 | ## License 356 | 357 | The MIT License (MIT). Please see [License File](LICENSE.md) for more information. 358 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Meta Pixel integration for Laravel 2 | 3 | [![Latest Version on Packagist](https://img.shields.io/packagist/v/combindma/laravel-facebook-pixel.svg?style=flat-square)](https://packagist.org/packages/combindma/laravel-facebook-pixel) 4 | [![GitHub Tests Action Status](https://img.shields.io/github/actions/workflow/status/combindma/laravel-facebook-pixel/run-tests.yml?branch=main&label=tests&style=flat-square)](https://github.com/combindma/laravel-facebook-pixel/actions?query=workflow%3ATests+branch%3Amaster) 5 | [![GitHub Code Style Action Status](https://img.shields.io/github/actions/workflow/status/combindma/laravel-facebook-pixel/fix-php-code-style-issues.yml?branch=main&label=code%20style&style=flat-square)](https://github.com/combindma/laravel-facebook-pixel/actions?query=workflow%3A"Check+%26+fix+styling"+branch%3Amaster) 6 | [![Total Downloads](https://img.shields.io/packagist/dt/combindma/laravel-facebook-pixel.svg?style=flat-square)](https://packagist.org/packages/combindma/laravel-facebook-pixel) 7 | 8 | A Complete Meta pixel implementation for your Laravel application. 9 | 10 | ## About Combind Agency 11 | 12 | [Combine Agency](https://combind.ma?utm_source=github&utm_medium=banner&utm_campaign=package_name) is a leading web development agency specializing in building innovative and high-performance web applications using modern technologies. Our experienced team of developers, designers, and project managers is dedicated to providing top-notch services tailored to the unique needs of our clients. 13 | 14 | If you need assistance with your next project or would like to discuss a custom solution, please feel free to [contact us](mailto:hello@combind.ma) or visit our [website](https://combind.ma?utm_source=github&utm_medium=banner&utm_campaign=package_name) for more information about our services. Let's build something amazing together! 15 | 16 | 17 | ## Introduction 18 | 19 | This package provides a smooth integration of Meta Pixel, along with a straightforward implementation of the latest Conversions API, enhancing your overall experience. 20 | - [Documentation for version 4.0 - older version](README-v4.md) 21 | 22 | ## Upgrading to Version 5 23 | 24 | If you are upgrading from version 4, please refer to our [Version 5 Migration Guide](upgrade-v4-to-v5.md) for detailed instructions on how to make a smooth transition. 25 | 26 | 27 | ## Pre-requisites 28 | 29 | ### Register a Meta Pixel 30 | 31 | To get started with the Meta pixel, you must have a pixel registered: [Read this guide](https://web.facebook.com/business/help/952192354843755). 32 | 33 | ### Conversions API 34 | 35 | If you plan to use Conversions API then you need to: 36 | 37 | #### Obtain An Access Token 38 | To use the Conversions API, you need to generate an access token, which will be passed as a parameter in every API call. 39 | 40 | Refer to [Conversions API Guide](https://developers.facebook.com/docs/marketing-api/conversions-api/get-started) to learn more. 41 | 42 | 43 | ## Installation 44 | 45 | You can install the package via composer: 46 | 47 | ```bash 48 | composer require combindma/laravel-facebook-pixel 49 | ``` 50 | 51 | Optionally, you can publish the views using: 52 | 53 | ```bash 54 | php artisan vendor:publish --tag="meta-pixel-views" 55 | ``` 56 | 57 | You can publish the config file with: 58 | 59 | ```bash 60 | php artisan vendor:publish --tag="meta-pixel-config" 61 | ``` 62 | 63 | This is the contents of the published config file: 64 | 65 | ```php 66 | return [ 67 | /* 68 | * The Meta pixel id, should be a code that looks something like "1202417153106158". 69 | */ 70 | 'pixel_id' => env('META_PIXEL_ID', ''), 71 | 72 | /* 73 | * The key under which data is saved to the session with flash. 74 | */ 75 | 'session_key' => env('META_PIXEL_SESSION_KEY', config('app.name').'_metaPixel'), 76 | 77 | /* 78 | * Only if you plan using Conversions API for server events 79 | * To use the Conversions API, you need an access token. For Documentation please see: https://developers.facebook.com/docs/marketing-api/conversions-api/get-started 80 | */ 81 | 'token' => env('META_PIXEL_TOKEN', ''), 82 | 83 | /* 84 | * Enable or disable advanced matching. Useful for adjusting user privacy. 85 | */ 86 | 'advanced_matching_enabled' => env('META_PIXEL_ADVANCED_MATCHING_ENABLED', true), 87 | 88 | /* 89 | * Enable or disable script rendering. Useful for local development. 90 | */ 91 | 'enabled' => env('META_PIXEL_ENABLED', false), 92 | 93 | /* 94 | * Enable or disable logging. Useful for debugging. 95 | */ 96 | 'logging' => env('META_PIXEL_LOGGING', false), 97 | 98 | /* 99 | * This is used to test server events 100 | */ 101 | 'test_event_code' => env('META_TEST_EVENT_CODE'), 102 | ]; 103 | ``` 104 | 105 | If you plan on using the [flash-functionality](#flashing-data-for-the-next-request) you must register the MetaPixelMiddleware: 106 | 107 | Global Middleware: 108 | ```php 109 | ->withMiddleware(function (Middleware $middleware) { 110 | $middleware->append(MetaPixelMiddleware::class); 111 | }) 112 | ``` 113 | Or Assigning Middleware to Routes (recommended if you have admin routes): 114 | ```php 115 | Route::group(['middleware' => [MetaPixelMiddleware::class]], static function () { 116 | 117 | }); 118 | ``` 119 | 120 | ## Usage - Meta Pixel 121 | 122 | ### Include scripts in Blade 123 | 124 | Insert head view after opening head tag, and body view after opening body tag 125 | 126 | ```html 127 | 128 | 129 | 130 | 131 | 132 | 133 | 134 | 135 | ``` 136 | 137 | If you use UUID as user id you should add userIdAsString attribute to the head component: 138 | ```html 139 | 140 | 141 | 142 | ``` 143 | 144 | To add an event, use the `track()` function. 145 | 146 | ```php 147 | // CheckoutController.php 148 | use Combindma\FacebookPixel\Facades\MetaPixel; 149 | 150 | public function index() 151 | { 152 | MetaPixel::track('Purchase', ['currency' => 'USD', 'value' => 30.00]); 153 | return view('thank-you'); 154 | } 155 | ``` 156 | 157 | This renders: 158 | 159 | ```html 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | ``` 170 | 171 | You can also specify a unique event ID for any of your events so that, if you plan using the conversions API you avoid duplications. 172 | 173 | ```php 174 | //For example your order id 175 | MetaPixel::track('Purchase', ['currency' => 'USD', 'value' => 30.00], '123456'); 176 | 177 | //Or create a unique id using 178 | $eventId = uniqid('ViewContent_', true); 179 | MetaPixel::track('ViewContent', [], $eventId); 180 | ``` 181 | 182 | 183 | #### Flashing data for the next request 184 | 185 | The package can also set event to render on the next request. This is useful for setting data after an internal redirect. 186 | 187 | ```php 188 | // ContactController.php 189 | use Combindma\FacebookPixel\Facades\MetaPixel; 190 | 191 | public function postContact() 192 | { 193 | // Do contact form stuff... 194 | MetaPixel::flashEvent('Lead', [ 195 | 'content_name' => 'Auto Insurance', 196 | 'content_category' => 'Quote', 197 | 'value' => 400.00, 198 | 'currency' => 'USD' 199 | ]); 200 | return redirect()->action('ContactController@getContact'); 201 | } 202 | ``` 203 | 204 | After a form submit, the following event will be parsed on the contact page: 205 | 206 | ```html 207 | 208 | 209 | 210 | 211 | 212 | 213 | 223 | 224 | 225 | ``` 226 | 227 | ### Available Methods 228 | 229 | ```php 230 | use Combindma\FacebookPixel\Facades\MetaPixel; 231 | 232 | // Retrieve your Pixel id 233 | $id = MetaPixel::pixelId(); 234 | // Set Pixel id on the fly 235 | MetaPixel::setPixelId('XXXXXXXX'); 236 | // Set Pixel token on the fly 237 | MetaPixel::setToken('XXXXXXXX'); 238 | // Check whether script rendering is enabled 239 | $enabled = MetaPixel::isEnabled(); // true|false 240 | // Enable and disable script rendering on the fly 241 | MetaPixel::enable(); 242 | MetaPixel::disable(); 243 | // Add event to the event layer (automatically renders right before the pixel script). Setting new values merges them with the previous ones. 244 | MetaPixel::track('eventName', ['attribute' => 'value']); 245 | MetaPixel::track('eventName', ['attribute' => 'value'], 'event_id'); //with an event id 246 | MetaPixel::track('eventName'); //without properties 247 | MetaPixel::track('eventName', [], 'event_id'); //with an event id but without properties 248 | // Flash event for the next request. Setting new values merges them with the previous ones. 249 | MetaPixel::flashEvent('eventName', ['attribute' => 'value']); 250 | MetaPixel::flashEvent('eventName', ['attribute' => 'value'], 'event_id'); //with an event id 251 | MetaPixel::flashEvent('eventName'); //without properties 252 | //Clear the event layer. 253 | MetaPixel::clear(); 254 | ``` 255 | 256 | ### Custom Events 257 | 258 | You can also track a specific custom event on your website. This feature is not available for flashed events. 259 | 260 | ```php 261 | use Combindma\FacebookPixel\Facades\MetaPixel; 262 | 263 | // In your controller 264 | MetaPixel::trackCustom('CUSTOM-EVENT-NAME', ['custom_parameter' => 'ABC', 'value' => 10.00, 'currency' => 'USD']); 265 | //With an event ID 266 | MetaPixel::trackCustom('CUSTOM-EVENT-NAME', ['custom_parameter' => 'ABC', 'value' => 10.00, 'currency' => 'USD'], 'EVENT_ID'); 267 | ``` 268 | 269 | This renders: 270 | 271 | ```html 272 | 273 | 274 | 275 | 276 | 277 | 278 | 283 | 284 | 285 | ``` 286 | 287 | ### Advanced matching 288 | 289 | This package provides by default advanced matching. We retrieve the email and the user id from authenticated user and include it in the Pixel base code fbq('init') function call as a third parameter. 290 | You can disable it by adding META_PIXEL_ADVANCED_MATCHING_ENABLED=false in your .env file 291 | 292 | ```html 293 | 294 | 295 | 303 | 304 | 305 | 306 | 307 | 308 | ``` 309 | 310 | ### Macroable 311 | 312 | Adding events to pages can become a repetitive process. Since this package isn't supposed to be opinionated on what your events should look like, the MetaPixel is macroable. 313 | 314 | ```php 315 | use Combindma\FacebookPixel\Facades\MetaPixel; 316 | 317 | //include this in your macrobale file 318 | MetaPixel::macro('purchase', function ($product) { 319 | MetaPixel::track('Purchase', [ 320 | 'currency' => 'EUR', 321 | 'value' => $product->price 322 | ]); 323 | }); 324 | 325 | //in your controller 326 | MetaPixel::purchase($product); 327 | ``` 328 | 329 | 330 | ## Usage - Conversions API 331 | 332 | If you plan on using [Conversions API](https://developers.facebook.com/docs/marketing-api/conversions-api/get-started) functionalities. Yous should specify the token in your .env file first. 333 | 334 | For every request yous should specify a unique event id for handling Pixel Duplicate Events and Conversions API. 335 | 336 | This is how you can start: 337 | 338 | ```php 339 | use Combindma\FacebookPixel\Facades\MetaPixel; 340 | use FacebookAds\Object\ServerSide\Content; 341 | use FacebookAds\Object\ServerSide\CustomData; 342 | use FacebookAds\Object\ServerSide\DeliveryCategory; 343 | use FacebookAds\Object\ServerSide\UserData; 344 | 345 | //Prepare User Data first. 346 | // By default, the IP Address, User Agent and fbc/fbp cookies are added. 347 | $user_data = MetaPixel::userData()->setEmail('joe@eg.com')->setPhone('12345678901'); 348 | 349 | $content = (new Content()) 350 | ->setProductId('product123') 351 | ->setQuantity(1) 352 | ->setDeliveryCategory(DeliveryCategory::HOME_DELIVERY); 353 | 354 | $custom_data = (new CustomData()) 355 | ->setContents(array($content)) 356 | ->setCurrency('usd') 357 | ->setValue(123.45); 358 | 359 | $eventId = uniqid('prefix_'); 360 | 361 | //send request 362 | MetaPixel::send('Purchase', $eventId ,$custom_data, $user_data); 363 | ``` 364 | 365 | If you don't specify the $user_data parameter, by default we retrieve the email & the id from Auth::user() if the user is authenticated. 366 | We use the user id as a same external_id in Meta Pixel and conversions API 367 | 368 | ```php 369 | MetaPixel::send('Purchase', $eventId, $custom_data); 370 | ``` 371 | 372 | If you want to test server events, you need to specify the FACEBOOK_TEST_EVENT_CODE in your .env file. By default, this test code will be sent in all API request. 373 | 374 | So Don't forget to delete after you finish your server tests. 375 | 376 | You can use the [Playload Helper](https://developers.facebook.com/docs/marketing-api/conversions-api/payload-helper) to learn more about the requests to send. 377 | 378 | ## Testing 379 | 380 | ```bash 381 | composer test 382 | ``` 383 | 384 | ## Contributing 385 | 386 | Please see [CONTRIBUTING](CONTRIBUTING.md) for details. 387 | 388 | ## Security Vulnerabilities 389 | 390 | Please review [our security policy](../../security/policy) on how to report security vulnerabilities. 391 | 392 | ## Credits 393 | 394 | - [Combind](https://github.com/Combindma) 395 | - [All Contributors](../../contributors) 396 | 397 | ## License 398 | 399 | The MIT License (MIT). Please see [License File](LICENSE.md) for more information. 400 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "combindma/laravel-facebook-pixel", 3 | "description": "Meta pixel integration for Laravel", 4 | "keywords": [ 5 | "combindma", 6 | "meta-pixel", 7 | "laravel" 8 | ], 9 | "homepage": "https://github.com/combindma/laravel-facebook-pixel", 10 | "license": "MIT", 11 | "authors": [ 12 | { 13 | "name": "Combind", 14 | "email": "webmaster@combind.ma", 15 | "role": "Developer" 16 | } 17 | ], 18 | "require": { 19 | "php": "^8.3", 20 | "facebook/php-business-sdk": "^22.0", 21 | "illuminate/contracts": "^11.0|^12.0", 22 | "spatie/laravel-package-tools": "^1.11" 23 | }, 24 | "require-dev": { 25 | "laravel/pint": "^1.0", 26 | "nunomaduro/collision": "^7.0|^8.0", 27 | "larastan/larastan": "^3.0", 28 | "orchestra/testbench": "^9.0|^10.0", 29 | "pestphp/pest": "^3.0", 30 | "pestphp/pest-plugin-arch": "^3.0", 31 | "pestphp/pest-plugin-laravel": "^3.0", 32 | "phpstan/extension-installer": "^1.1", 33 | "phpstan/phpstan-deprecation-rules": "^2.0", 34 | "phpstan/phpstan-phpunit": "^2.0" 35 | }, 36 | "autoload": { 37 | "psr-4": { 38 | "Combindma\\FacebookPixel\\": "src/" 39 | } 40 | }, 41 | "autoload-dev": { 42 | "psr-4": { 43 | "Combindma\\FacebookPixel\\Tests\\": "tests/" 44 | } 45 | }, 46 | "scripts": { 47 | "post-autoload-dump": "@php ./vendor/bin/testbench package:discover --ansi", 48 | "analyse": "vendor/bin/phpstan analyse", 49 | "test": "vendor/bin/pest", 50 | "test-coverage": "vendor/bin/pest --coverage", 51 | "format": "vendor/bin/pint" 52 | }, 53 | "config": { 54 | "sort-packages": true, 55 | "allow-plugins": { 56 | "pestphp/pest-plugin": true, 57 | "phpstan/extension-installer": true 58 | } 59 | }, 60 | "extra": { 61 | "laravel": { 62 | "providers": [ 63 | "Combindma\\FacebookPixel\\FacebookPixelServiceProvider" 64 | ] 65 | } 66 | }, 67 | "minimum-stability": "dev", 68 | "prefer-stable": true 69 | } 70 | -------------------------------------------------------------------------------- /config/meta-pixel.php: -------------------------------------------------------------------------------- 1 | env('META_PIXEL_ID', ''), 8 | 9 | /* 10 | * The key under which data is saved to the session with flash. 11 | */ 12 | 'session_key' => env('META_PIXEL_SESSION_KEY', config('app.name').'_metaPixel'), 13 | 14 | /* 15 | * Only if you plan using Conversions API for server events 16 | * To use the Conversions API, you need an access token. For Documentation please see: https://developers.facebook.com/docs/marketing-api/conversions-api/get-started 17 | */ 18 | 'token' => env('META_PIXEL_TOKEN', ''), 19 | 20 | /* 21 | * Enable or disable advanced matching. Useful for adjusting user privacy. 22 | */ 23 | 'advanced_matching_enabled' => env('META_PIXEL_ADVANCED_MATCHING_ENABLED', true), 24 | 25 | /* 26 | * Enable or disable script rendering. Useful for local development. 27 | */ 28 | 'enabled' => env('META_PIXEL_ENABLED', false), 29 | 30 | /* 31 | * Enable or disable logging. Useful for debugging. 32 | */ 33 | 'logging' => env('META_PIXEL_LOGGING', false), 34 | 35 | /* 36 | * This is used to test server events 37 | */ 38 | 'test_event_code' => env('META_TEST_EVENT_CODE'), 39 | ]; 40 | -------------------------------------------------------------------------------- /phpstan-baseline.neon: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/combindma/laravel-facebook-pixel/e4ff52ed41dcccc48ad966ad2d49e32ef65a920a/phpstan-baseline.neon -------------------------------------------------------------------------------- /phpstan.neon.dist: -------------------------------------------------------------------------------- 1 | includes: 2 | - phpstan-baseline.neon 3 | 4 | parameters: 5 | level: 4 6 | paths: 7 | - src 8 | - config 9 | ignoreErrors: 10 | - 11 | message: '#Access to an undefined property Illuminate\\Foundation\\Auth\\User::\$email#' 12 | tmpDir: build/phpstan 13 | checkOctaneCompatibility: true 14 | checkModelProperties: true 15 | checkMissingIterableValueType: false 16 | 17 | -------------------------------------------------------------------------------- /resources/views/body.blade.php: -------------------------------------------------------------------------------- 1 | @if($metaPixel->isEnabled()) 2 | @unless(empty($eventLayer)) 3 | 4 | 15 | 16 | @endunless 17 | @unless(empty($customEventLayer)) 18 | 19 | 30 | 31 | @endunless 32 | @endif 33 | -------------------------------------------------------------------------------- /resources/views/head.blade.php: -------------------------------------------------------------------------------- 1 | @if($metaPixel->isEnabled()) 2 | 3 | 23 | 26 | 27 | @endif 28 | -------------------------------------------------------------------------------- /src/Components/Body.php: -------------------------------------------------------------------------------- 1 | metaPixel = $metaPixel; 19 | $this->eventLayer = $this->metaPixel->getEventLayer()->toArray(); 20 | $this->customEventLayer = $this->metaPixel->getCustomEventLayer()->toArray(); 21 | } 22 | 23 | public function render() 24 | { 25 | return view('meta-pixel::body'); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /src/Components/Head.php: -------------------------------------------------------------------------------- 1 | metaPixel->isEnabled() && empty($this->metaPixel->pixelId())) { 17 | throw new Exception('You need to set a Meta Pixel Id in .env file.'); 18 | } 19 | 20 | if ($this->metaPixel->isEnabled() && empty($this->metaPixel->sessionKey())) { 21 | throw new Exception('You need to set a session key for Meta Pixel in .env file.'); 22 | } 23 | } 24 | 25 | public function render() 26 | { 27 | return view('meta-pixel::head'); 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /src/EventLayer.php: -------------------------------------------------------------------------------- 1 | data = $data; 14 | } 15 | 16 | public function set(string $eventName, array $parameters = [], ?string $eventID = null): void 17 | { 18 | $this->data = Arr::add($this->data, $eventName, ['data' => $parameters, 'event_id' => $eventID]); 19 | } 20 | 21 | public function merge(array $newData): void 22 | { 23 | $this->data = array_merge($this->data, $newData); 24 | } 25 | 26 | public function clear(): void 27 | { 28 | $this->data = []; 29 | } 30 | 31 | public function toArray(): array 32 | { 33 | return $this->data; 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /src/Facades/MetaPixel.php: -------------------------------------------------------------------------------- 1 | name('meta-pixel') 16 | ->hasConfigFile('meta-pixel') 17 | ->hasViewComponents( 18 | 'metapixel', 19 | Head::class, 20 | Body::class 21 | ) 22 | ->hasViews(); 23 | } 24 | 25 | public function packageBooted(): void {} 26 | 27 | public function registeringPackage(): void 28 | { 29 | $this->app->singleton(MetaPixel::class, function () { 30 | return new MetaPixel; 31 | }); 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /src/MetaPixel.php: -------------------------------------------------------------------------------- 1 | enabled = config('meta-pixel.enabled'); 50 | $this->logEnabled = config('meta-pixel.logging'); 51 | $this->advancedMatchingEnabled = config('meta-pixel.advanced_matching_enabled'); 52 | $this->pixelId = config('meta-pixel.pixel_id'); 53 | $this->token = config('meta-pixel.token'); 54 | $this->sessionKey = config('meta-pixel.session_key'); 55 | $this->testEventCode = config('meta-pixel.test_event_code'); 56 | $this->eventLayer = new EventLayer; 57 | $this->customEventLayer = new EventLayer; 58 | $this->flashEventLayer = new EventLayer; 59 | $this->userData = new UserData; 60 | } 61 | 62 | public function pixelId(): string 63 | { 64 | return (string) $this->pixelId; 65 | } 66 | 67 | public function sessionKey() 68 | { 69 | return $this->sessionKey; 70 | } 71 | 72 | public function token() 73 | { 74 | return $this->token; 75 | } 76 | 77 | public function testEnabled(): bool 78 | { 79 | return (bool) $this->testEventCode; 80 | } 81 | 82 | public function isEnabled(): bool 83 | { 84 | return $this->enabled; 85 | } 86 | 87 | public function isAdvancedMatchingEnabled(): bool 88 | { 89 | return $this->advancedMatchingEnabled; 90 | } 91 | 92 | public function enable(): void 93 | { 94 | $this->enabled = true; 95 | } 96 | 97 | public function disable(): void 98 | { 99 | $this->enabled = false; 100 | } 101 | 102 | public function setPixelId(int|string $id): void 103 | { 104 | $this->pixelId = (string) $id; 105 | } 106 | 107 | public function setToken(string $token): void 108 | { 109 | $this->token = (string) $token; 110 | } 111 | 112 | /** 113 | * Add event to the event layer. 114 | */ 115 | public function track(string $eventName, array $parameters = [], ?string $eventId = null): void 116 | { 117 | $this->eventLayer->set($eventName, $parameters, $eventId); 118 | } 119 | 120 | /** 121 | * Add custom event to the event layer. 122 | */ 123 | public function trackCustom(string $eventName, array $parameters = [], ?string $eventId = null): void 124 | { 125 | $this->customEventLayer->set($eventName, $parameters, $eventId); 126 | } 127 | 128 | /** 129 | * Add event data to the event layer for the next request. 130 | */ 131 | public function flashEvent(string $eventName, array $parameters = [], ?string $eventId = null): void 132 | { 133 | $this->flashEventLayer->set($eventName, $parameters, $eventId); 134 | } 135 | 136 | public function userData(): UserData 137 | { 138 | if ($user = $this->getUser()) { 139 | return $this->userData 140 | ->setEmail($user['em']) 141 | ->setExternalId($user['external_id']) 142 | ->setClientIpAddress(Request::ip()) 143 | ->setClientUserAgent(Request::userAgent()) 144 | ->setFbc(Arr::get($_COOKIE, '_fbc')) 145 | ->setFbp(Arr::get($_COOKIE, '_fbp')); 146 | } 147 | 148 | return $this->userData 149 | ->setClientIpAddress(Request::ip()) 150 | ->setClientUserAgent(Request::userAgent()) 151 | ->setFbc(Arr::get($_COOKIE, '_fbc')) 152 | ->setFbp(Arr::get($_COOKIE, '_fbp')); 153 | } 154 | 155 | /** 156 | * Send request using Conversions API 157 | */ 158 | public function send(string $eventName, string $eventID, CustomData $customData, ?UserData $userData = null): ?EventResponse 159 | { 160 | if (! $this->isEnabled()) { 161 | return null; 162 | } 163 | if (empty($this->token())) { 164 | throw new Exception('You need to set a token in your .env file to use the Conversions API.'); 165 | } 166 | 167 | $api = Api::init(null, null, $this->token); 168 | 169 | if ($this->logEnabled) { 170 | $api->setLogger(new CurlLogger); 171 | } 172 | 173 | $event = (new Event) 174 | ->setEventName($eventName) 175 | ->setEventTime(time()) 176 | ->setEventId($eventID) 177 | ->setEventSourceUrl(URL::current()) 178 | ->setUserData($userData ?? $this->userData()) 179 | ->setCustomData($customData) 180 | ->setActionSource(ActionSource::WEBSITE); 181 | 182 | $request = (new EventRequest($this->pixelId()))->setEvents([$event]); 183 | 184 | if ($this->testEnabled()) { 185 | $request->setTestEventCode($this->testEventCode); 186 | } 187 | 188 | try { 189 | return $request->execute(); 190 | } catch (Exception $e) { 191 | if ($this->logEnabled) { 192 | Log::error($e); 193 | } 194 | } 195 | 196 | return null; 197 | } 198 | 199 | /** 200 | * Merge array data with the event layer. 201 | */ 202 | public function merge(array $eventSession): void 203 | { 204 | $this->eventLayer->merge($eventSession); 205 | } 206 | 207 | /** 208 | * Retrieve the event layer. 209 | */ 210 | public function getEventLayer(): EventLayer 211 | { 212 | return $this->eventLayer; 213 | } 214 | 215 | /** 216 | * Retrieve custom event layer. 217 | */ 218 | public function getCustomEventLayer(): EventLayer 219 | { 220 | return $this->customEventLayer; 221 | } 222 | 223 | /** 224 | * Retrieve the event layer's data for the next request. 225 | */ 226 | public function getFlashedEvent(): array 227 | { 228 | return $this->flashEventLayer->toArray(); 229 | } 230 | 231 | /** 232 | * Retrieve the email to use it advanced matching. 233 | * To use advanced matching we will get the email if the user is authenticated 234 | */ 235 | public function getUser(): ?array 236 | { 237 | if ($this->isAdvancedMatchingEnabled() && Auth::check()) { 238 | return [ 239 | 'em' => strtolower(Auth::user()->email), 240 | 'external_id' => Auth::user()->id, 241 | ]; 242 | } 243 | 244 | return null; 245 | } 246 | 247 | public function clear(): void 248 | { 249 | $this->eventLayer = new EventLayer; 250 | } 251 | } 252 | -------------------------------------------------------------------------------- /src/MetaPixelMiddleware.php: -------------------------------------------------------------------------------- 1 | facebookPixel = $facebookPixel; 17 | $this->session = $session; 18 | } 19 | 20 | public function handle($request, Closure $next) 21 | { 22 | if ($this->session->has($this->facebookPixel->sessionKey())) { 23 | $this->facebookPixel->merge($this->session->get($this->facebookPixel->sessionKey())); 24 | } 25 | $response = $next($request); 26 | 27 | $this->session->flash($this->facebookPixel->sessionKey(), $this->facebookPixel->getFlashedEvent()); 28 | 29 | return $response; 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /upgrade-v4-to-v5.md: -------------------------------------------------------------------------------- 1 | # v5 Migration Guide: Steps to Upgrade from v4 2 | 3 | Migrating to the latest version of our package is straightforward and involves a few key changes to ensure compatibility and take advantage of new features. Please follow the steps below to complete your migration. 4 | 5 | ## Configuration Changes 6 | 7 | ### 1. Config File Rename 8 | The configuration file has been renamed to `meta-pixel`. Please update any references to the old config file in your project. 9 | 10 | ### 2. Environment Variable Prefix Change 11 | Replace the `FACEBOOK_` prefix in your environment variables with `META_`. For example, change `FACEBOOK_PIXEL_ID` to `META_PIXEL_ID`. 12 | 13 | ## Feature Additions 14 | 15 | ### 3. Advanced Matching Enabled 16 | We have added a new feature `advanced_matching_enabled` to the configuration file, which is enabled by default. This feature enhances user tracking accuracy. 17 | 18 | ## Middleware Update 19 | 20 | ### 4. Middleware Name Update 21 | The middleware name has been updated to `MetaPixelMiddleware`. Update your middleware references accordingly. 22 | 23 | ## Facade Updates 24 | 25 | ### 5. Facade Call Changes 26 | All facade calls should now be made to `MetaPixel` instead of the previous facade name. 27 | 28 | ## Syntax Updates in HTML 29 | 30 | ### 6. Head and Body Tag Names 31 | Update the head and body tags in your HTML files using the new syntax for better integration: 32 | 33 | ```html 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | ``` 44 | 45 | --------------------------------------------------------------------------------