Skip to main content
Version: 2026.2

Frontend JavaScript

When targeting is enabled and at least one targeting rule or target group is configured, Pimcore injects a snippet of JavaScript into HTML responses to frontend GET requests. Requests made in the admin context, non-GET requests and non-HTML responses such as JSON or redirects are skipped. This snippet carries information the frontend needs about the application state (for example, whether debug mode is enabled) and loads the script bundles/pimcorepersonalization/js/targeting.js, which handles the frontend behavior of the targeting engine (for example, it exposes an API to set the visitor ID). All targeting logic runs inside the window._ptg object.

The frontend code provides a few extension points, documented on this page.

Setting a Custom Visitor ID

targeting.js exposes a method to set a visitor ID programmatically. This sets the visitor ID and stores it in the visitor ID cookie delivered to the backend.

_ptg.api.setVisitorId('my-custom-visitor-id');
warning

Use a unique visitor ID for each visitor.

Change or Extend the Code Snippet Injected into the Response

The TargetingCodeGenerator generates the code injected into the response and fires a TargetingEvents::TARGETING_CODE event (see Events). Use this event to influence the data and the template used to render the code snippet:

<?php

// src/EventListener/TargetingCodeListener.php

namespace App\EventListener;

use Pimcore\Bundle\PersonalizationBundle\Event\Targeting\TargetingCodeEvent;
use Pimcore\Bundle\PersonalizationBundle\Event\TargetingEvents;
use Pimcore\Bundle\PersonalizationBundle\Targeting\Code\TargetingCodeGenerator;
use Symfony\Component\EventDispatcher\EventSubscriberInterface;

class TargetingCodeListener implements EventSubscriberInterface
{
public static function getSubscribedEvents(): array
{
return [
TargetingEvents::TARGETING_CODE => 'onTargetingCode',
];
}

public function onTargetingCode(TargetingCodeEvent $event): void
{
// add code to a code block (see TargetingCodeGenerator and the default
// template for a list of blocks and their location)
$event
->getBlock(TargetingCodeGenerator::BLOCK_BEFORE_SCRIPT)
->append([
'console.log("Custom targeting code");'
]);

// completely override the rendered template
$event->setTemplate('@App/Targeting/targetingCode.html.twig');
}
}

The listener above sets a custom template which can either extend the core one or define a completely custom output:

{# templates/Targeting/targetingCode.html.twig #} 

{% extends '@PimcorePersonalization/Targeting/targetingCode.html.twig' %}

{% block beforeScriptTag %}
{{ parent() }}

<script type="text/javascript">
console.log('Custom targeting template');
</script>
{% endblock %}

Frontend Data Providers

Some conditions or data providers may need data from the frontend. To make this possible, a backend implementation can call $visitorInfo->addFrontendDataProvider() during the matching process to tell the frontend it needs data from a specific provider. You implement and register these frontend data providers in the frontend JS; they're expected to deliver their data back to the backend somehow, for example by storing it in a cookie or sending it through an async request.

Currently, this feature is only sparsely used, but the GeoLocation data provider, which can read the visitor location from browser geolocation data, informs the frontend that it needs data from the geolocation frontend data provider. Pimcore adds this information to the browser response, triggering targeting.js to execute this frontend data provider. The data provider then stores its data in a cookie, consumed by the backend data provider on the next request.

Implementing a Custom Frontend Data Provider

Register your frontend data provider on the window._ptg.dataProviders object before targeting.js loads. Here's a simple provider that does nothing more than log the current user agent to the console:

// /public/js/targeting/frontend.js

(function () {
window._ptg = window._ptg || {};
window._ptg.dataProviders = window._ptg.dataProviders || {};

window._ptg.dataProviders.userAgent = function() {
console.log('The current user agent is ' + navigator.userAgent);
};
}());

Reusing the example listener above, load your script through a custom code snippet template:

{# templates/Targeting/targetingCode.html.twig #} 

{% block targetingScript %}
<script type="text/javascript" src="{{ asset('bundles/app/js/targeting/frontend.js') }}"></script>
{{ parent() }}
{% endblock %}

To actually execute the provider, add the following call somewhere in your matching process, for example while loading data from a data provider:

$visitorInfo->addFrontendDataProvider('userAgent');