By default we offer for most popular Content Management System such as:
and Moden Frameworks such as:
a SDK, which utilize WebSocket for Realtime Analytics. If none of them is suitable, you can utilize our standalone JavaScript Tracker to ship your data to for your Organization Workspace and Project.
It offers all features except Web-hooks for Notificatons and Realtime Session Tracking.
For GravCMS, WordPress, Joomla, and any website that can add a
<script>tag.
Endpoints are:
The PVYanalytics standalone tracker is a single JavaScript file served from your PVYanalytics instance. It requires no npm installation, no build step, and no framework — just one <script> tag in your HTML.
Privacy-first: No cookies, no cross-site tracking, no fingerprinting. Uses sessionStorage for session management (30-minute inactivity timeout). All data is sent via sendBeacon or fetch with keepalive: true.
cm123abc456def)pvy_live_...)Add this to your website’s <head> or before </body>:
<script
src="https://analytics.pvy.swiss/tracker.js"
data-project-id="YOUR_PROJECT_ID"
data-token="pvy_live_YOUR_TOKEN_HERE"
data-api-url="https://analytics.pvy.swiss"
defer
></script>
| Attribute | Description | Example |
|---|---|---|
data-project-id |
Your project ID from the dashboard | cm123abc456def |
data-token |
API token (starts with pvy_live_ or pvy_test_) |
pvy_live_abc123... |
data-api-url |
Your PVYanalytics instance URL | https://analytics.pvy.swiss |
In the dashboard, go to Project Settings → API Tokens → edit your token → add allowed domains (e.g., iqcom.cloud, pvy.swiss). This prevents unauthorized sites from using your token.
Edit your theme’s base template file:
user/themes/your-theme/templates/base.html.twig
Add the script tag before </head>:
{# PVYanalytics Tracker #}
<script
src="https://analytics.pvy.swiss/tracker.js"
data-project-id="YOUR_PROJECT_ID"
data-token="pvy_live_YOUR_TOKEN_HERE"
data-api-url="https://analytics.pvy.swiss"
defer
></script>
Create a simple GravCMS plugin that injects the script:
user/plugins/pvyanalytics/pvyanalytics.php
<?php
namespace Grav\Plugin;
use Grav\Common\Plugin;
class PvyanalyticsPlugin extends Plugin
{
public static function getSubscribedEvents()
{
return [
'onAssetsInitialized' => ['onAssetsInitialized', 0]
];
}
public function onAssetsInitialized()
{
$config = $this->config->get('plugins.pvyanalytics');
if (!$config || !$config['enabled']) return;
$projectId = $config['project_id'];
$token = $config['token'];
$apiUrl = $config['api_url'] ?? 'https://analytics.pvy.swiss';
$this->grav['assets']->addInlineJs(
"document.addEventListener('DOMContentLoaded', function() {" .
" var s = document.createElement('script');" .
" s.src = '{$apiUrl}/tracker.js';" .
" s.setAttribute('data-project-id', '{$projectId}');" .
" s.setAttribute('data-token', '{$token}');" .
" s.setAttribute('data-api-url', '{$apiUrl}');" .
" s.defer = true;" .
" document.head.appendChild(s);" .
"});"
);
}
}
With a blueprints file:
user/plugins/pvyanalytics/blueprints.yaml
name: PVYanalytics
version: 1.0.0
description: PVYanalytics web analytics integration
author: PVY.swiss
license: MIT
form:
validation: loose
fields:
enabled:
type: toggle
label: Plugin enabled
default: 1
options:
1: Enabled
0: Disabled
validate:
type: bool
project_id:
type: text
label: Project ID
placeholder: "cm123abc456def"
token:
type: text
label: API Token
placeholder: "pvy_live_..."
api_url:
type: text
label: API URL
default: "https://analytics.pvy.swiss"
placeholder: "https://analytics.pvy.swiss"
Add to wp-content/themes/your-theme/functions.php:
function pvyanalytics_tracker() {
?>
<script
src="https://analytics.pvy.swiss/tracker.js"
data-project-id="YOUR_PROJECT_ID"
data-token="pvy_live_YOUR_TOKEN_HERE"
data-api-url="https://analytics.pvy.swiss"
defer
></script>
<?php
}
add_action('wp_head', 'pvyanalytics_tracker');
Create wp-content/plugins/pvyanalytics/pvyanalytics.php:
<?php
/**
* Plugin Name: PVYanalytics Tracker
* Description: Privacy-first web analytics by PVY.swiss
* Version: 1.0.0
* Author: PVY.swiss
*/
function pvyanalytics_tracker() {
$project_id = get_option('pvyanalytics_project_id', '');
$token = get_option('pvyanalytics_token', '');
$api_url = get_option('pvyanalytics_api_url', 'https://analytics.pvy.swiss');
if (!$project_id || !$token) return;
?>
<script
src="<?php echo esc_url($api_url); ?>/tracker.js"
data-project-id="<?php echo esc_attr($project_id); ?>"
data-token="<?php echo esc_attr($token); ?>"
data-api-url="<?php echo esc_url($api_url); ?>"
defer
></script>
<?php
}
add_action('wp_head', 'pvyanalytics_tracker');
// Settings page
function pvyanalytics_settings_page() {
add_options_page(
'PVYanalytics Settings',
'PVYanalytics',
'manage_options',
'pvyanalytics',
'pvyanalytics_settings_html'
);
}
add_action('admin_menu', 'pvyanalytics_settings_page');
function pvyanalytics_settings_html() {
if (isset($_POST['pvyanalytics_submit'])) {
update_option('pvyanalytics_project_id', sanitize_text_field($_POST['project_id']));
update_option('pvyanalytics_token', sanitize_text_field($_POST['token']));
update_option('pvyanalytics_api_url', esc_url_raw($_POST['api_url']));
echo '<div class="notice notice-success"><p>Settings saved.</p></div>';
}
$project_id = get_option('pvyanalytics_project_id', '');
$token = get_option('pvyanalytics_token', '');
$api_url = get_option('pvyanalytics_api_url', 'https://analytics.pvy.swiss');
?>
<div class="wrap">
<h1>PVYanalytics Settings</h1>
<form method="post">
<table class="form-table">
<tr>
<th scope="row"><label for="project_id">Project ID</label></th>
<td><input type="text" name="project_id" id="project_id"
value="<?php echo esc_attr($project_id); ?>"
class="regular-text" placeholder="cm123abc456def" /></td>
</tr>
<tr>
<th scope="row"><label for="token">API Token</label></th>
<td><input type="text" name="token" id="token"
value="<?php echo esc_attr($token); ?>"
class="regular-text" placeholder="pvy_live_..." /></td>
</tr>
<tr>
<th scope="row"><label for="api_url">API URL</label></th>
<td><input type="text" name="api_url" id="api_url"
value="<?php echo esc_attr($api_url); ?>"
class="regular-text" /></td>
</tr>
</table>
<?php submit_button('Save Settings', 'primary', 'pvyanalytics_submit'); ?>
</form>
</div>
<?php
}
Add to your template’s index.php (before </head>):
<?php
$document = JFactory::getDocument();
$document->addCustomTag(
'<script src="https://analytics.pvy.swiss/tracker.js" ' .
'data-project-id="YOUR_PROJECT_ID" ' .
'data-token="pvy_live_YOUR_TOKEN_HERE" ' .
'data-api-url="https://analytics.pvy.swiss" defer></script>'
);
?>
Or for Joomla 4+:
<?php
$wa = $this->getWebAssetManager();
$wa->addInlineScript(
'var s = document.createElement("script");' .
's.src = "https://analytics.pvy.swiss/tracker.js";' .
's.setAttribute("data-project-id", "YOUR_PROJECT_ID");' .
's.setAttribute("data-token", "pvy_live_YOUR_TOKEN_HERE");' .
's.setAttribute("data-api-url", "https://analytics.pvy.swiss");' .
's.defer = true;' .
'document.head.appendChild(s);'
);
?>
<!DOCTYPE html>
<html>
<head>
<title>My Website</title>
<script
src="https://analytics.pvy.swiss/tracker.js"
data-project-id="YOUR_PROJECT_ID"
data-token="pvy_live_YOUR_TOKEN_HERE"
data-api-url="https://analytics.pvy.swiss"
defer
></script>
</head>
<body>
<h1>Hello World</h1>
</body>
</html>
Add data-pvyanalytics-event to any clickable element:
<button data-pvyanalytics-event="signup-button-click">
Sign Up
</button>
<a href="/download" data-pvyanalytics-event="download-link-click">
Download PDF
</a>
The tracker automatically listens for clicks on elements with this attribute and sends events to /api/track-event.
After the tracker loads, use the global window.pvyanalytics object:
// Track a custom event
window.pvyanalytics.trackEvent("newsletter-signup", "form-submit", {
source: "footer",
page: window.location.pathname
});
// Manually track a page view (useful for SPA route changes)
window.pvyanalytics.trackPageView();
| Field | Source | Example |
|---|---|---|
url |
window.location.href |
https://iqcom.cloud/about |
referrer |
document.referrer |
https://google.com/ |
userAgent |
navigator.userAgent |
Mozilla/5.0... |
language |
navigator.language |
en-US |
timezone |
Intl.DateTimeFormat |
Europe/Zurich |
viewport |
window.innerWidth/Height |
1920x1080 |
screen |
window.screen.width/height |
2560x1440 |
title |
document.title |
About Us — iqcom.cloud |
sessionId |
Generated (sessionStorage) | 1697234567890-abc123 |
utm_source |
URL parameter | google |
utm_medium |
URL parameter | cpc |
utm_campaign |
URL parameter | summer2026 |
utm_term |
URL parameter | analytics |
utm_content |
URL parameter | banner1 |
sessionStorage only)The tracker automatically detects SPA navigation by intercepting:
history.pushStatehistory.replaceStatepopstate event (back/forward)hashchange eventNo additional configuration needed — page views are tracked automatically on route changes.
sessionStorageclick, keydown, mousemove, scroll, touchstartbeforeunloaddata-project-id and data-token are correctallowedDomains list (or leave empty for all domains)curl -s https://analytics.pvy.swiss/tracker.js | head -5/api/track — should return 200 or 307The tracking endpoints have Access-Control-Allow-Origin: * — CORS should not be an issue. If you see CORS errors, verify you’re hitting the correct API URL.
If your site uses HTTPS, make sure data-api-url also uses HTTPS (https://analytics.pvy.swiss, not http://).
# Test page view tracking
curl -X POST https://analytics.pvy.swiss/api/track \
-H "Content-Type: application/json" \
-H "Authorization: Bearer pvy_live_YOUR_TOKEN" \
-d '{
"url": "https://iqcom.cloud/test",
"timestamp": "'$(date -u +%Y-%m-%dT%H:%M:%SZ)'",
"projectId": "YOUR_PROJECT_ID",
"userAgent": "curl-test/1.0"
}'
After the tracker loads, run in the browser console:
// Check if tracker is loaded
console.log(window.pvyanalytics);
// Track a test page view
window.pvyanalytics.trackPageView();
// Track a test event
window.pvyanalytics.trackEvent("test-event", "console-test", {
source: "developer-console"
});
Then check the dashboard at https://analytics.pvy.swiss — the event should appear within seconds in the real-time view.