Joomla System Plugin providing server-side tracking for websites without an e-shop (no VirtueMart required). A lightweight variant of Sema Track for VirtueMart. Conversion = visit to a thank-you page after form submission or AJAX form detection.
| Parameter | Value |
|---|---|
| Plugin ID | plg_system_semakin_sst_web |
| CMS | Joomla 4.x / 5.x / 6.x |
| PHP | 8.1+ |
| Current version | 1.0.4 |
Supported platforms: GA4, Google Ads, Sklik.cz.
1. Requirements
- Joomla 4.x, 5.x or 6.x
- PHP 8.1 or newer
- MySQL 5.7+ / MariaDB 10.3+
- A GDPR consent component: StoreJExtensions GDPR, Sema Cookie Consent, or CookieYes (or Manual mode)
Note: This plugin does not require VirtueMart. For e-shops with VirtueMart, use Sema Track for VirtueMart (
plg_system_semakin_sst).
2. Installation
Obtaining the Package
Download the file plg_system_semakin_sst_web-1.0.4.zip from SemaHub (semakin.cz).
Installation Steps
- Log in to the Joomla administration panel.
- Navigate to System > Install > Extensions.
- Upload the
plg_system_semakin_sst_web-1.0.4.zipfile. - After installation, the plugin creates two database tables:
#__semakin_sst_web_logand#__semakin_sst_web_queue.
Upgrade: Same procedure as installation. Joomla uses
method="upgrade". All data in the log and queue tables is preserved.
3. Enabling the Plugin
After installation, the plugin must be manually enabled:
- Go to System > Manage > Plugins.
- Search for
semakin_sst_weborServer-Side Tracking. - Click the plugin name and set Status = Enabled.
- Configure the plugin parameters (see sections below).
4. Basic Configuration
Open the plugin settings: System > Plugins > click the plugin name.
Tab: Basic Settings
| Parameter | Default | Description |
|---|---|---|
| Tracking Enabled | Yes | Global switch for all server-side tracking. |
| Test Mode | No | When on, GA4 events go to the debug endpoint. Disable in production. |
| GDPR Component | StoreJExtensions | Source of user consent (see section 5). |
| Default Consent Layer | 0 (Anonymous) | Used when consent cannot be read or Manual mode is selected. |
| Conversion Event Name | generate_lead | GA4 event name for the conversion. Change only if needed. |
| Conversion Value | 0 | Monetary value assigned to each conversion (for Google Ads reporting). |
| Conversion Currency | CZK | ISO 4217 currency code for the conversion value. |
| Log Retention (days) | 90 | Records older than this are automatically deleted. |
| Queue Retention (days) | 30 | Processed/failed queue items older than this are deleted. |
| Inline Queue Processing (%) | 5 | Probability of retry queue processing on each request. Set to 0 when using Task Scheduler. |
5. GDPR Consent Setup
The plugin uses a three-layer consent model:
| Layer | Name | What is sent |
|---|---|---|
| L0 | Anonymous | Anonymised events: truncated IP, temporary UUID, no cookies |
| L1 | Analytics | GA4 with client_id, session_id |
| L2 | Marketing | Conversions for GA4/Ads/Sklik; hashed email/phone (Enhanced Conversions) |
Supported GDPR Components
| Component | Detection method |
|---|---|
| StoreJExtensions GDPR (com_gdpr) | JS bridge reads Local Storage, sets cookie semakin_sst_cl |
| Sema Cookie Consent | JS bridge reads Local Storage (scc_cookie_consent), sets cookie semakin_sst_cl |
| CookieYes | Direct cookie read (cookieyes-consent) |
| Manual | Fixed consent level (no detection) |
Important: Cookie Category
The bridge cookie semakin_sst_cl must be categorised as Necessary (Category 1) in your consent component, NOT as Analytics or Marketing. It is a technical cookie that communicates consent status from JS to PHP – it does not track anything.
Timing: The bridge cookie takes effect on the next page load. For conversion events this is always fine – the visitor has loaded at least 2 pages before submitting a form.
6. Conversion Detection
The plugin detects conversions (form submissions) using one of three modes, configured via the Conversion Mode setting.
Mode: URL Match (default)
The plugin compares the current page URL (REQUEST_URI) with the configured Conversion URL (e.g. /dekujeme, /thank-you). When the visitor lands on the thank-you page after a form submission, a generate_lead event is triggered.
| Parameter | Description |
|---|---|
| Conversion URL | Path to the thank-you page (e.g. /dekujeme). Matched against REQUEST_URI. |
Mode: AJAX Form
For forms submitted via AJAX (without a page redirect), such as SP Page Builder, RSForm, or custom JavaScript forms. The plugin injects JavaScript that intercepts AJAX responses. When a successful form submission is detected, a cookie semakin_sst_web_ajax_cv=1 is set. On the next page load, the plugin reads this cookie and triggers a generate_lead event.
| Parameter | Description |
|---|---|
| AJAX Form Selector | Optional CSS selector to limit which forms are tracked (e.g. #contact-form, .sp-form). Leave empty to track all forms. |
The JS intercept covers three AJAX methods:
- jQuery
$(document).ajaxComplete()– most Joomla components - XMLHttpRequest monkey-patch – non-jQuery AJAX
- Fetch API monkey-patch – modern implementations
Mode: Both
Combines URL match and AJAX detection. Deduplication is shared – only one conversion per session regardless of mode.
Deduplication
All modes share a session-level deduplication flag (semakin_sst_web.lead_tracked). Only one generate_lead event is sent per session.
7. Form PII Capture
The plugin injects JavaScript before </body> that captures email and phone from form fields for use in Enhanced Conversions (Google Ads, Sklik EID).
How It Works
- JS listens for
submitandclickevents on forms and buttons. - When a form is submitted, JS searches for
input[type="email"]andinput[type="tel"]fields. - Found values are hashed with SHA-256 in the browser using the Web Crypto API.
- Hashes are stored in cookie
semakin_sst_form_pii(JSON:{"eh":"sha256...","ph":"sha256..."}), 30-minute expiry. - PHP reads the hashes and passes them to Google Ads (
hashedEmail/hashedPhoneNumber) and Sklik (eid).
GDPR: No plaintext PII ever leaves the browser. The cookie contains only SHA-256 hashes. PHP never sees the original email or phone number.
8. Google Analytics 4
Tab: GA4
| Parameter | Description |
|---|---|
| GA4 Enabled | Enable sending events via Measurement Protocol v2. |
| Measurement ID | Format G-XXXXXXXXXX. Found in GA4 > Admin > Data Streams. |
| API Secret | Measurement Protocol secret. Found in GA4 > Data Streams > Measurement Protocol API secrets. |
| _ga Cookie Name | Default _ga. Change only if using a custom cookie name. |
| Send Anonymous Events (L0) | Send basic events even without consent (anonymised). Recommended: Yes. |
| Client Deduplication | Adds event_id to prevent double-counting if also using gtag.js. |
Tracked Events
| Event | Detection | Min. consent |
|---|---|---|
session_start | First page in session | L0 |
page_view | Every frontend page | L0 |
generate_lead | URL match / AJAX detection | L0 |
Client ID Fallback
Without gtag.js, the _ga cookie does not exist. The plugin automatically creates a fallback cookie semakin_sst_cid with a GA4-compatible format (2-year expiry).
9. Google Ads
Tab: Google Ads
| Parameter | Description |
|---|---|
| Google Ads Enabled | Enable conversion upload via Conversion API v23. |
| Conversion Action ID | Numeric ID of the conversion action (not AW- format). |
| Developer Token | From Google Ads API Center. |
| Customer ID | Client account ID (format XXX-XXX-XXXX). |
| MCC Customer ID | Optional. Manager account ID if using MCC. |
| OAuth Client ID | From Google Cloud Console. |
| OAuth Client Secret | Paste into textarea (password fields may truncate). |
| OAuth Refresh Token | Paste into textarea. OAuth consent screen must be in Production mode. |
| Enhanced Conversions | Send hashed email/phone for better attribution. Hashes come from the Form PII Capture JS. |
Important Notes
- Conversion action type: Must be “Import from clicks” (not “Website”).
- GCLID/GBRAID: The plugin captures click IDs from URL parameters and stores them in cookies (90 days). On Safari/iOS, Google sends
gbraidinstead ofgclid. - Enhanced Conversions for Leads: Must be enabled in Google Ads > Settings. The plugin sends SHA-256 hashes captured by the Form PII Capture JS.
- Timeout: Google Ads API requests use a 5-second timeout.
- Only
generate_leadevents, only at L2.
10. Sklik.cz
Tab: Sklik
| Parameter | Description |
|---|---|
| Sklik Enabled | Enable Sklik conversion and retargeting tracking. |
| Conversion Goal ID | Numeric ID from your Sklik conversion code (id parameter). |
| Retargeting List ID | Optional. Retargeting audience ID. |
| Send Hashed Email (EID) | SHA-256 email hash for better attribution (L2 only). |
How It Works
Sklik does not have a server-side API. The plugin injects JavaScript snippets (rc.js) before </body>:
- Retargeting (
rc.retargetingHit) on every page (L0+) - Conversions (
rc.conversionHit) ongenerate_lead(L0+) - Consent parameter: Dynamic –
consent:0without marketing consent,consent:1with consent - EID: Only sent at L2
The rc.js script is loaded as a synchronous <script> tag (required by Sklik).
CSP: If the site uses Content-Security-Policy, add
https://c.seznam.cztoscript-src,connect-src, andimg-src. Addhttps://h.seznam.cztoconnect-src.
11. Retry Queue and Task Scheduler
When an API call fails, the event is stored in the #__semakin_sst_web_queue table for automatic retry with exponential backoff (1 min > 5 min > 15 min).
Two Processing Methods
| Method | Configuration |
|---|---|
| Inline processing | Set “Inline Queue Processing” to 5–10%. Processes on random HTTP requests. |
| Joomla Task Scheduler | Create tasks in System > Scheduled Tasks. Set inline processing to 0%. |
Task Scheduler Setup
- Go to System > Scheduled Tasks > New.
- Create “Semakin SST Web: Process Retry Queue” – run every 15 minutes.
- Create “Semakin SST Web: Cleanup Old Records” – run once daily.
- Set inline processing to 0% in plugin settings.
- Verify: click “Run Test” – exit code 0 = OK.
Task Scheduler requires a cron job or “lazy cron”. For reliable operation:
*/5 * * * * php /path/to/joomla/cli/joomla.php scheduler:run > /dev/null 2>&1
12. Logging and Diagnostics
Tab: Logging
| Parameter | Description |
|---|---|
| Logging Enabled | Global logging switch. |
| Log Level | Minimum level for file log only. DB log always writes regardless of this setting. |
| Log to Database | Write to #__semakin_sst_web_log. Recommended: always on (required for deduplication). |
| Log to File | Write to logs/semakin_sst_web.php in the Joomla logs folder. |
| Max Retry Attempts | Maximum retry attempts (default 3). |
Checking the DB Log
SELECT event_name, platform, consent_level, status, http_status, created_at
FROM #__semakin_sst_web_log
ORDER BY id DESC
LIMIT 20;
Replace #__ with your table prefix.
13. Uninstallation
- Go to System > Manage > Extensions.
- Search for
semakin_sst_web. - Select and uninstall.
The uninstaller drops both tables (#__semakin_sst_web_log and #__semakin_sst_web_queue).
14. Troubleshooting
No Events in Database
- Verify the plugin is enabled (Status = Enabled).
- Check that
services/provider.phpexists in the plugin directory on the server. - Verify the bridge cookie
semakin_sst_clis set (DevTools > Application > Cookies). - If the cookie is missing, check that your GDPR component is configured and the bridge JS is not being stripped.
consent_level Is Always 0
- The bridge cookie
semakin_sst_clis missing or blocked. - Check that
semakin_sst_clis categorised as Necessary in your consent component. - On the first page after installation, consent is always L0 (the bridge cookie needs one page load to initialise).
generate_lead Not Firing (URL Match)
- Verify the Conversion URL matches the actual thank-you page path.
- The path is compared against
REQUEST_URI– check for an exact match (case-sensitive). - Verify the visitor has not already triggered a conversion in the current session (deduplication).
generate_lead Not Firing (AJAX)
- Check DevTools > Cookies for
semakin_sst_web_ajax_cv=1after form submission. - If the cookie is missing, the JS intercept did not detect a successful AJAX response. Check browser console for errors.
- If the cookie is present but no event appears in the DB log, navigate to another page – the event fires on the next page load.
- If using the AJAX Form Selector, verify the CSS selector matches your form element.
Google Ads Conversions Not Visible in Dashboard
- Verify the conversion action is type “Import from clicks” (not Website).
- Check that GCLID/GBRAID is present in the DB log payload.
- Verify OAuth consent screen is in Production mode.
- Check that Enhanced Conversions for Leads is enabled.
Sklik Code Not Firing
- Verify
rc.jsis loaded as a synchronous<script>tag (check page source). - If the site uses CSP, add the required domains (see CSP note in Sklik tab).
- Check browser console for errors.
PII Hashes Missing in Conversions
- Verify the form contains
input[type="email"]orinput[type="tel"]fields. - Check DevTools > Cookies for
semakin_sst_form_piiafter form submission. - The cookie has a 30-minute expiry – if the conversion fires later, hashes may be gone.
How Tracking Works (Overview)
- A visitor loads a page on the website.
- The plugin collects
page_viewandsession_startevents. - The consent level is determined from the GDPR component (via bridge cookie).
- Events are anonymised according to the consent level.
- Server-side senders dispatch events to GA4.
- JavaScript is injected before
</body>: Sklik retargeting, consent bridge, form PII capture. - When the visitor submits a form:
- URL match: The thank-you page triggers a
generate_leadevent. - AJAX: JS detects the AJAX response, sets a cookie, and the event fires on the next page load.
- URL match: The thank-you page triggers a
- The
generate_leadevent is sent to GA4, Google Ads, and Sklik. - Failed API calls are queued for automatic retry.
Cookies Used by the Plugin
| Cookie | Purpose | Expiry | Set by |
|---|---|---|---|
semakin_sst_cl | Consent bridge (LS to PHP) | 24h | JS bridge |
semakin_sst_cid | GA4 client_id fallback | 2 years | PHP |
semakin_sst_gclid | GCLID from URL (Google Ads) | 90 days | PHP |
semakin_sst_gbraid | GBRAID from URL (Safari/iOS) | 90 days | PHP |
semakin_sst_form_pii | SHA-256 hashes of email/phone | 30 min | JS |
semakin_sst_web_ajax_cv | AJAX conversion detected | 30 min | JS |
semakin_sst_clmust be in Necessary cookie category. Other cookies belong in Analytics or Marketing categories.
Launch Checklist
- Plugin installed and enabled
- GDPR component selected and configured
- Bridge cookie
semakin_sst_clcategorised as Necessary - Conversion mode selected (URL match / AJAX / Both)
- Conversion URL configured (if using URL match)
- AJAX form selector configured (if using AJAX, optional)
- GA4: Measurement ID and API Secret configured
- Google Ads: Conversion action created as “Import from clicks”
- Google Ads: OAuth credentials in textarea fields, consent screen in Production
- Google Ads: Enhanced Conversions for Leads enabled
- Sklik: Conversion ID and Retargeting ID configured
- CSP headers updated (if applicable)
- DB logging enabled
- Test Mode DISABLED
- Inline queue processing set (or Task Scheduler configured)
- Test form submission completed and verified in DB log and platform dashboards