- Documentation >
- Recommendations >
- Integration with Raptor >
- Tracking with PHP API
Tracking with PHP API
You can interact directly with the service using the PHP API for advanced tracking usage.
Advanced usage – direct interaction with the service
EventMapper method
The recommended method, providing full control over event tracking, is EventMapper method.
It allows to interact directly with the service, supporting advanced use cases not covered by default implementation.
Check the following example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 | <php>
use Ibexa\Contracts\ConnectorRaptor\Tracking\EventMapperInterface;
use Ibexa\Contracts\ConnectorRaptor\Tracking\ServerSideTrackingDispatcherInterface;
use Ibexa\Contracts\ConnectorRaptor\Tracking\EventType;
class MyCustomService
{
public function __construct(
private readonly EventMapperInterface $eventMapper,
private ServerSideTrackingDispatcherInterface $trackingDispatcher,
) {}
public function trackProductView(ProductInterface $product, string $url): void
{
// Map product to VisitEventData automatically
$eventData = $this->eventMapper->map(EventType::VISIT, $product);
// Send tracking event
$this->trackingDispatcher->dispatch($eventData);
}
}
</php>
|
Manual EventData creation
Manual creation of EventData allows precise control over the events sent to the service.
It enables to define custom event parameters, track specific user interactions, and tailor data collection to advanced use cases.
Check the following example:
1
2
3
4
5
6
7
8
9
10
11
12
13 | <php>
use Ibexa\Contracts\ConnectorRaptor\Tracking\Event\VisitEventData;
$eventData = new VisitEventData(
productId: $product->getCode(),
productName: $product->getName(),
categoryPath: '25#Electronics;26#Smartphones', // Build manually
currency: 'USD',
itemPrice: '999.99'
);
$this->trackingDispatcher->dispatch($eventData);
</php>
|
Example - event subscriber
If you need to track events automatically based on application events, you can use Event Subscriber.
It reacts to specific events in the application and triggers tracking logic without the need to add it manually in templates.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39 | <php>
use Ibexa\Contracts\ConnectorRaptor\Tracking\EventMapperInterface;
use Ibexa\Contracts\ConnectorRaptor\Tracking\ServerSideTrackingDispatcherInterface;
use Ibexa\Contracts\ConnectorRaptor\Tracking\EventType;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;
use Symfony\Component\HttpKernel\Event\ResponseEvent;
use Symfony\Component\HttpKernel\KernelEvents;
class ProductViewTrackingSubscriber implements EventSubscriberInterface
{
public function __construct(
private readonly EventMapperInterface $eventMapper,
private ServerSideTrackingDispatcherInterface $trackingDispatcher,
) {}
public static function getSubscribedEvents(): array
{
return [KernelEvents::RESPONSE => ['onResponse', -10]];
}
public function onResponse(ResponseEvent $event): void
{
if (!$event->isMainRequest()) {
return;
}
$request = $event->getRequest();
// Example: track only if request has specific attribute
$product = $request->attributes->get('product');
if (!$product) {
return;
}
$eventData = $this->eventMapper->map(EventType::VISIT, $product);
$this->trackingDispatcher->dispatch($eventData);
}
}
</php>
|
Tracking events
The following events are supported and can be triggered from Twig templates:
Product visit event
This event tracks product page visits by users.
It's the most common e-commerce tracking event used to capture product views for analytics, recommendation models, and user behavior processing.
Required data:
- Product object - defines the product being tracked. It implements
ProductInterface so the system can read its information (for example, ID, price, category).
Example:
1
2
3
4
5
6
7
8
9
10
11
12
13 | # templates/product/view.html.twig #}
{% extends 'base.html.twig' %}
{% block content %}
<div class="product-details">
<h1>{{ product.name }}</h1>
<p>{{ product.description }}</p>
<div class="price">{{ product.price }}</div>
</div>
{# Track product visit #}
{{ ibexa_tracking_track_event('visit', product) }}
{% endblock %}
|
Content visit event
This event tracks content page visits by users.
It can used to check content views for analytics, personalization, and user behavior tracking.
- Content object - defines the content being tracked.
Basket event
This event tracks when a product is added to the shopping basket.
It catches user interest and helps with conversion tracking and product recommendations.
Required data:
- Product object - defines the product being added to the basket.
- Context array with basket information - provides optional data about the basket, like quantity or basket ID, to provide context for the event.
Example:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26 | # templates/cart/add_confirmation.html.twig #}
{% extends 'base.html.twig' %}
{% block content %}
<div class="cart-notification">
<p>Product "{{ product.name }}" has been added to your cart!</p>
<p>Quantity: {{ addedQuantity }}</p>
</div>
{# Build basket content string: "SKU:quantity;SKU:quantity" #}
{% set basketContent = [] %}
{% for item in basket.items %}
{% set basketContent = basketContent|merge([item.product.code ~ ':' ~ item.quantity]) %}
{% endfor %}
{# Track basket addition #}
{% set basketContext = {
'basketContent': basketContent|join(';'),
'basketId': basket.id,
'quantity': addedQuantity
} %}
{{ ibexa_tracking_track_event('basket', product, basketContext) }}
<a href="{{ path('cart_view') }}">View Cart</a>
{% endblock %}
|
Simplified example with Twig filter:
| {# If you have a custom Twig filter to format basket content #}
{% set basketContext = {
'basketContent': basket|format_basket_content, {# Returns "SKU-1:2;SKU-2:1;SKU-3:5" #}
'basketId': basket.id,
'quantity': addedQuantity
} %}
{{ ibexa_tracking_track_event('basket', product, basketContext) }}
|
Simplified example with Twig filter:
| {# If you have a custom Twig filter to format basket content #}
{% set basketContext = {
'basketContent': basket|format_basket_content, {# Returns "SKU-1:2;SKU-2:1;SKU-3:5" #}
'basketId': basket.id,
'quantity': addedQuantity
} %}
{{ ibexa_tracking_track_event('basket', product, basketContext) }}
|
Complex integration
For more complex integrations, the Ibexa Design Engine can be used to override parts or entire templates that render the tracking script.
| Template |
Description |
Example project path |
@ibexadesign/ibexa/tracking/script.html.twig |
Responsible for creating the window.raptor object and handling consent. Loads tracking only if consent is given and listens for the enableTracking event. |
templates/themes/standard/ibexa/tracking/script.html.twig |
@ibexadesign/ibexa/tracking/script.js.twig |
Handles the loading of the tracking JavaScript. |
templates/themes/standard/ibexa/tracking/script.js.twig |
Available variables are:
- customer_id - type: string, Raptor account ID used for tracking
- script_url - type: string, URL of the tracking script, by default
//deliver.raptorstatic.com/script/raptor-3.0.min.js, configurable through ibexa.connector.raptor.tracking_script.url Symfony Dependency Injection container parameter (not SiteAccess-aware)
- has_consented - type: boolean, indicates whether the user has given consent, default value:
false (unless explicitly passed as function argument)
- debug - type: boolean,
kernel.debug Symfony dependency injection container parameter, typically true in development environments and false in production
The default template defines a Twig block that includes script.js.twig.
When extending the template, this block can be overridden to customize the script’s behavior.
You can override the default templates, either individually or both at the same time.
Extension
It's possible to extend script.html.twig by combining the Ibexa Design Engine with standard Symfony template reference in templates/themes/standard/ibexa/tracking/script.html.twig:
| {% extends '@IbexaConnectorRaptor/themes/standard/ibexa/tracking/script.html.twig' %}
{% block ibexa_tracking_script %}
console.log('My custom tracking script, but relying on loadTracking function.');
{% endblock %}
|
In most cases, the preferred approach is to do the opposite:
| <script type="text/javascript">
if (myCustomConsentIsGiven) {
{{ include('@ibexadesign/ibexa/tracking/script.js.twig', {'customer_id': customer_id}) }}
}
</script>
|
Example custom integration
Example custom integration with TermsFeed:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30 | ``` html
<!-- Cookie Consent by TermsFeed https://www.TermsFeed.com -->
<script type="text/javascript" src="https://www.termsfeed.com/public/cookie-consent/4.2.0/cookie-consent.js" charset="UTF-8"></script>
<script type="text/javascript" charset="UTF-8">
document.addEventListener('DOMContentLoaded', function () {
cookieconsent.run({
"notice_banner_type": "simple",
"consent_type": "implied",
"palette": "dark",
"language": "en",
"page_load_consent_levels": ["strictly-necessary"],
"notice_banner_reject_button_hide": false,
"preferences_center_close_button_hide": false,
"page_refresh_confirmation_buttons": false,
"website_name": "Ibexa Storefront",
"callbacks": {
"scripts_specific_loaded": (level) => {
switch(level) {
case 'tracking':
document.dispatchEvent(new CustomEvent('enableTracking'));
break;
}
}
},
"callbacks_force": true
});
});
</script>
<noscript>Free cookie consent management tool by <a href="https://www.termsfeed.com/">TermsFeed</a></noscript>
<!-- End Cookie Consent by TermsFeed https://www.TermsFeed.com -->
|
```