Magento 2 Events & Observers – Practical Guide

Events and Observers in Magento 2 provide a powerful way to extend and customize functionality without touching core code. An event is dispatched at key points in the system, and observers listen to those events and execute custom logic in response.

1. Full Observer Example (events.xml + Observer Class)

Example: Log a message every time a product is added to the cart on the frontend. We will observe the native event checkout_cart_product_add_after.

Module namespace: Vendor/EventsDemo

1.1. Declare the observer in etc/frontend/events.xml

<?xml version="1.0"?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd"> <event name="checkout_cart_product_add_after"> <observer name="vendor_eventsdemo_log_add_to_cart" instance="Vendor\EventsDemo\Observer\LogAddToCart" /> </event> </config>

1.2. Create the Observer class

File: app/code/Vendor/EventsDemo/Observer/LogAddToCart.php

<?php namespace Vendor\EventsDemo\Observer; use Magento\Framework\Event\Observer; use Magento\Framework\Event\ObserverInterface; use Psr\Log\LoggerInterface; class LogAddToCart implements ObserverInterface { /** * @var LoggerInterface */ protected $logger; public function __construct( LoggerInterface $logger ) { $this->logger = $logger; } /** * Execute observer * * @param Observer $observer * @return void */ public function execute(Observer $observer) { // Product that has been added $quoteItem = $observer->getEvent()->getQuoteItem(); $product = $quoteItem->getProduct(); $this->logger->info(sprintf( 'Product added to cart: %s (ID: %d, SKU: %s, Qty: %s)', $product->getName(), $product->getId(), $product->getSku(), $quoteItem->getQty() )); } }

After enabling the module and clearing cache, adding a product to the cart will write a log entry to var/log/system.log (or another configured log).

2. Custom Event Creation & Dispatching

You can also create your own custom events and dispatch them from any class that has access to the event manager.

2.1. Dispatch a custom event in a service class

File: app/code/Vendor/EventsDemo/Model/Notifier.php

<?php namespace Vendor\EventsDemo\Model; use Magento\Framework\Event\ManagerInterface as EventManager; class Notifier { /** * @var EventManager */ protected $eventManager; public function __construct( EventManager $eventManager ) { $this->eventManager = $eventManager; } /** * Example method that dispatches a custom event * * @param int $customerId * @param string $message * @return void */ public function notifyCustomer($customerId, $message) { // Your business logic here... // Dispatch custom event $this->eventManager->dispatch( 'vendor_eventsdemo_customer_notified', [ 'customer_id' => $customerId, 'message' => $message ] ); } }

2.2. Observe the custom event

File: app/code/Vendor/EventsDemo/etc/events.xml (global scope)

<?xml version="1.0"?> <config xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="urn:magento:framework:Event/etc/events.xsd"> <event name="vendor_eventsdemo_customer_notified"> <observer name="vendor_eventsdemo_log_customer_notify" instance="Vendor\EventsDemo\Observer\LogCustomerNotify" /> </event> </config>

File: app/code/Vendor/EventsDemo/Observer/LogCustomerNotify.php

<?php namespace Vendor\EventsDemo\Observer; use Magento\Framework\Event\Observer; use Magento\Framework\Event\ObserverInterface; use Psr\Log\LoggerInterface; class LogCustomerNotify implements ObserverInterface { protected $logger; public function __construct( LoggerInterface $logger ) { $this->logger = $logger; } public function execute(Observer $observer) { $customerId = (int) $observer->getEvent()->getData('customer_id'); $message = (string) $observer->getEvent()->getData('message'); $this->logger->info( 'Custom event fired: vendor_eventsdemo_customer_notified', ['customer_id' => $customerId, 'message' => $message] ); } }

Any time notifyCustomer() is called, your custom event is dispatched and the observer runs.

3. Common Magento 2 Events (Quick Reference)

Here is a small, practical list of commonly used events:

  • controller_action_predispatch – Before any controller action executes.
  • customer_login – After a customer successfully logs in.
  • customer_logout – After a customer logs out.
  • customer_register_success – After a customer account is created.
  • checkout_cart_product_add_after – After a product is added to cart.
  • sales_quote_save_after – After a quote is saved.
  • sales_order_place_after – After an order is placed.
  • sales_order_save_after – After an order record is saved.
  • catalog_product_save_before – Before a product is saved.
  • catalog_product_save_after – After a product is saved.
  • cms_page_save_after – After a CMS page is saved.
  • newsletter_subscriber_save_after – After a newsletter subscription changes.

You can search the Magento codebase for $this->eventManager->dispatch( to discover many more events.

4. Observer vs Plugin (Interceptor)

Both Observers and Plugins can change behavior, but they are designed for different kinds of customizations.

Aspect Observer Plugin (Interceptor)
Concept Listens to an event and runs when that event is dispatched. Wraps a public method of a specific class (before/around/after).
Scope Event-centric, can affect multiple areas that dispatch the same event. Class-method centric, only affects one class method signature.
Best for Reacting to business events (order placed, customer login, etc.). Fine-tuning or altering method behavior/arguments/return values.
Coupling Loosely coupled to dispatching code (only depends on event name/data). Tightly coupled to concrete class and method name.
Performance Generally lightweight; triggered only when the event fires. Introduces interception overhead on every call of that method.
When to choose Use when there is an existing event or when you want to model a “business event” in your module. Use when you need to modify behavior where no suitable event exists, or you must change parameters/return values of a specific method.

In practice: prefer events/observers for high-level business actions, and plugins for low-level method-level changes.