PHP Quickstart
Get up and running with Zenovay analytics in your PHP application in under 5 minutes using native PHP HTTP functions to send events directly to the Zenovay tracking endpoint.
Zenovay does not have an official PHP SDK. Instead, you send events directly via HTTP to the tracking endpoint using PHP's built-in cURL or file_get_contents. This keeps your integration lightweight with zero external dependencies.
Basic Setup
1. Create a Zenovay Helper
Create a simple helper file for sending events:
<?php
// config/analytics.php
function zenovay_tracking_code(): string
{
return getenv('ZENOVAY_TRACKING_CODE') ?: '';
}
function zenovay_endpoint(): string
{
return 'https://api.zenovay.com/e/' . zenovay_tracking_code();
}
/**
* Send a custom event to Zenovay.
*/
function zenovay_track(
string $eventName,
string $url,
?string $visitorId = null,
?string $sessionId = null,
array $properties = []
): ?array {
$payload = [
'event_type' => 'custom',
'event_name' => $eventName,
'url' => $url,
'visitor_id' => $visitorId ?? bin2hex(random_bytes(16)),
'session_id' => $sessionId ?? bin2hex(random_bytes(16)),
'properties' => $properties,
'timestamp' => gmdate('Y-m-d\TH:i:s.v\Z'),
];
return zenovay_send($payload);
}
/**
* Send an identify event to Zenovay.
*/
function zenovay_identify(
string $userId,
string $email,
string $url,
?string $visitorId = null,
?string $sessionId = null,
array $extraTraits = []
): ?array {
$userProfile = array_merge(
['user_id' => $userId, 'email' => $email],
$extraTraits
);
$payload = [
'event_type' => 'identify',
'event_name' => 'user_identified',
'user_profile' => $userProfile,
'url' => $url,
'visitor_id' => $visitorId ?? bin2hex(random_bytes(16)),
'session_id' => $sessionId ?? bin2hex(random_bytes(16)),
'timestamp' => gmdate('Y-m-d\TH:i:s.v\Z'),
];
return zenovay_send($payload);
}
/**
* Send payload to Zenovay tracking endpoint via cURL.
*/
function zenovay_send(array $payload): ?array
{
$json = json_encode($payload);
$endpoint = zenovay_endpoint();
$ch = curl_init($endpoint);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $json,
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 5,
]);
$response = curl_exec($ch);
$error = curl_error($ch);
curl_close($ch);
if ($error) {
error_log("Zenovay tracking error: {$error}");
return null;
}
return json_decode($response, true);
}
?>
2. Add Client-Side Tracking
Add the Zenovay script to your HTML templates for automatic page view tracking:
<!-- templates/header.php -->
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title><?php echo htmlspecialchars($title); ?></title>
<!-- Zenovay Analytics -->
<script src="https://api.zenovay.com/z.js"
data-tracking-code="<?php echo htmlspecialchars(getenv('ZENOVAY_TRACKING_CODE')); ?>"
async></script>
</head>
<body>
3. Track Server-Side Events
Track events from your PHP code:
<?php
// signup.php
require_once __DIR__ . '/config/analytics.php';
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$email = $_POST['email'];
$name = $_POST['name'];
$plan = $_POST['plan'];
try {
// Create user account
$userId = createUser($email, $name, $plan);
// Track signup event
zenovay_track(
'signup_completed',
'https://yoursite.com/signup',
null,
null,
[
'plan' => $plan,
'source' => 'website',
'user_id' => (string) $userId,
]
);
echo json_encode(['success' => true, 'user_id' => $userId]);
} catch (Exception $e) {
http_response_code(500);
echo json_encode(['error' => $e->getMessage()]);
}
}
?>
Environment Configuration
Create a .env file:
# .env
ZENOVAY_TRACKING_CODE=your_tracking_code_here
Load environment variables using vlucas/phpdotenv:
composer require vlucas/phpdotenv
<?php
// bootstrap.php
require __DIR__ . '/vendor/autoload.php';
use Dotenv\Dotenv;
$dotenv = Dotenv::createImmutable(__DIR__);
$dotenv->load();
?>
Alternative: Using file_get_contents
If cURL is not available, you can use file_get_contents with a stream context:
<?php
/**
* Send payload to Zenovay using file_get_contents (no cURL required).
*/
function zenovay_send_fgc(array $payload): ?array
{
$json = json_encode($payload);
$endpoint = zenovay_endpoint();
$options = [
'http' => [
'method' => 'POST',
'header' => "Content-Type: application/json\r\n",
'content' => $json,
'timeout' => 5,
],
];
$context = stream_context_create($options);
$response = @file_get_contents($endpoint, false, $context);
if ($response === false) {
error_log('Zenovay tracking error: request failed');
return null;
}
return json_decode($response, true);
}
?>
Common Use Cases
Track User Identification
<?php
// login.php
require_once __DIR__ . '/config/analytics.php';
session_start();
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$email = $_POST['email'];
$password = $_POST['password'];
try {
$user = authenticateUser($email, $password);
// Store user in session
$_SESSION['user_id'] = $user['id'];
// Identify user in Zenovay
zenovay_identify(
(string) $user['id'],
$user['email'],
'https://yoursite.com/login',
null,
null,
[
'name' => $user['name'],
'plan' => $user['plan'] ?? null,
'created_at' => $user['created_at'],
]
);
// Track login event
zenovay_track(
'user_logged_in',
'https://yoursite.com/login',
null,
null,
[
'method' => 'password',
'user_id' => (string) $user['id'],
]
);
header('Location: /dashboard');
exit;
} catch (Exception $e) {
$error = 'Invalid credentials';
}
}
?>
Track E-commerce Events
<?php
// checkout.php
require_once __DIR__ . '/config/analytics.php';
session_start();
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$userId = $_SESSION['user_id'];
$cartItems = $_POST['cart_items'];
$total = $_POST['total'];
try {
// Process order
$order = createOrder($userId, $cartItems, $total);
// Track purchase
zenovay_track(
'purchase_completed',
'https://yoursite.com/checkout',
null,
null,
[
'order_id' => $order['id'],
'revenue' => $total,
'currency' => 'USD',
'user_id' => (string) $userId,
'items' => array_map(function ($item) {
return [
'product_id' => $item['id'],
'quantity' => $item['quantity'],
'price' => $item['price'],
];
}, $cartItems),
]
);
echo json_encode(['success' => true, 'order' => $order]);
} catch (Exception $e) {
http_response_code(500);
echo json_encode(['error' => $e->getMessage()]);
}
}
?>
Track API Usage
<?php
// api/generate.php
require_once __DIR__ . '/../config/analytics.php';
header('Content-Type: application/json');
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$input = json_decode(file_get_contents('php://input'), true);
$userId = $input['user_id'];
$model = $input['model'];
$prompt = $input['prompt'];
try {
$startTime = microtime(true);
$result = generateContent($model, $prompt);
$responseTime = (microtime(true) - $startTime) * 1000; // ms
// Track API usage
zenovay_track(
'api_request',
'https://yoursite.com/api/generate',
null,
null,
[
'endpoint' => '/api/generate',
'model' => $model,
'success' => true,
'response_time' => $responseTime,
'user_id' => (string) $userId,
]
);
echo json_encode($result);
} catch (Exception $e) {
// Track API error
zenovay_track(
'api_error',
'https://yoursite.com/api/generate',
null,
null,
[
'endpoint' => '/api/generate',
'error' => $e->getMessage(),
'user_id' => (string) $userId,
]
);
http_response_code(500);
echo json_encode(['error' => $e->getMessage()]);
}
}
?>
Middleware Pattern
Create reusable analytics middleware:
<?php
// middleware/AnalyticsMiddleware.php
require_once __DIR__ . '/../config/analytics.php';
class AnalyticsMiddleware
{
public function identifyUser(): void
{
if (session_status() === PHP_SESSION_NONE) {
session_start();
}
if (isset($_SESSION['user_id'])) {
$user = getUserById($_SESSION['user_id']);
if ($user) {
zenovay_identify(
(string) $user['id'],
$user['email'],
$this->getCurrentUrl(),
null,
null,
[
'name' => $user['name'],
'plan' => $user['plan'] ?? null,
]
);
}
}
}
public function trackPageView(): void
{
zenovay_track(
'page_viewed',
$this->getCurrentUrl(),
null,
null,
[
'page' => $_SERVER['REQUEST_URI'],
'referrer' => $_SERVER['HTTP_REFERER'] ?? null,
'user_agent' => $_SERVER['HTTP_USER_AGENT'] ?? null,
]
);
}
private function getCurrentUrl(): string
{
$scheme = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
return $scheme . '://' . $_SERVER['HTTP_HOST'] . $_SERVER['REQUEST_URI'];
}
}
// Usage in your pages
require_once __DIR__ . '/middleware/AnalyticsMiddleware.php';
$analytics = new AnalyticsMiddleware();
$analytics->identifyUser();
$analytics->trackPageView();
?>
Error Tracking
Set up global error tracking:
<?php
// error_handler.php
require_once __DIR__ . '/config/analytics.php';
function handleError($errno, $errstr, $errfile, $errline)
{
if (session_status() === PHP_SESSION_NONE) {
session_start();
}
zenovay_track(
'php_error',
'https://yoursite.com' . ($_SERVER['REQUEST_URI'] ?? ''),
null,
null,
[
'error_number' => $errno,
'error_message' => $errstr,
'error_file' => $errfile,
'error_line' => $errline,
'user_id' => isset($_SESSION['user_id']) ? (string) $_SESSION['user_id'] : null,
]
);
// Default error handling
return false;
}
function handleException($exception)
{
if (session_status() === PHP_SESSION_NONE) {
session_start();
}
zenovay_track(
'php_exception',
'https://yoursite.com' . ($_SERVER['REQUEST_URI'] ?? ''),
null,
null,
[
'exception_message' => $exception->getMessage(),
'exception_file' => $exception->getFile(),
'exception_line' => $exception->getLine(),
'exception_trace' => $exception->getTraceAsString(),
'user_id' => isset($_SESSION['user_id']) ? (string) $_SESSION['user_id'] : null,
]
);
http_response_code(500);
echo 'An error occurred. Please try again.';
}
set_error_handler('handleError');
set_exception_handler('handleException');
?>
Laravel Integration
For Laravel applications, create a service provider:
<?php
// app/Providers/ZenovayServiceProvider.php
namespace App\Providers;
use Illuminate\Support\ServiceProvider;
class ZenovayServiceProvider extends ServiceProvider
{
public function register()
{
$this->app->singleton('zenovay', function () {
return new class {
private string $endpoint;
public function __construct()
{
$trackingCode = config('services.zenovay.tracking_code');
$this->endpoint = "https://api.zenovay.com/e/{$trackingCode}";
}
public function track(string $eventName, string $url, array $properties = []): void
{
$payload = [
'event_type' => 'custom',
'event_name' => $eventName,
'url' => $url,
'visitor_id' => bin2hex(random_bytes(16)),
'session_id' => bin2hex(random_bytes(16)),
'properties' => $properties,
'timestamp' => now()->toIso8601ZuluString(),
];
$this->send($payload);
}
public function identify(string $userId, string $email, string $url, array $extraTraits = []): void
{
$payload = [
'event_type' => 'identify',
'event_name' => 'user_identified',
'user_profile' => array_merge(['user_id' => $userId, 'email' => $email], $extraTraits),
'url' => $url,
'visitor_id' => bin2hex(random_bytes(16)),
'session_id' => bin2hex(random_bytes(16)),
'timestamp' => now()->toIso8601ZuluString(),
];
$this->send($payload);
}
private function send(array $payload): void
{
try {
\Http::timeout(5)->post($this->endpoint, $payload);
} catch (\Exception $e) {
\Log::warning("Zenovay tracking error: {$e->getMessage()}");
}
}
};
});
}
}
// config/services.php
return [
// ...
'zenovay' => [
'tracking_code' => env('ZENOVAY_TRACKING_CODE'),
],
];
// Usage in controllers
public function store(Request $request)
{
$user = User::create($request->validated());
app('zenovay')->track(
'user_created',
$request->url(),
['plan' => $request->plan, 'user_id' => (string) $user->id]
);
return response()->json($user, 201);
}
WordPress Integration
Add to your theme's functions.php:
<?php
// functions.php
// Add tracking script to header
function zenovay_tracking_script()
{
$tracking_code = getenv('ZENOVAY_TRACKING_CODE');
if (!$tracking_code) return;
?>
<script src="https://api.zenovay.com/z.js"
data-tracking-code="<?php echo esc_attr($tracking_code); ?>"
async></script>
<?php
}
add_action('wp_head', 'zenovay_tracking_script');
// Helper to send events
function zenovay_send_event(string $eventName, array $properties = []): void
{
$trackingCode = getenv('ZENOVAY_TRACKING_CODE');
if (!$trackingCode) return;
$endpoint = "https://api.zenovay.com/e/{$trackingCode}";
$payload = json_encode([
'event_type' => 'custom',
'event_name' => $eventName,
'url' => home_url($_SERVER['REQUEST_URI'] ?? '/'),
'visitor_id' => bin2hex(random_bytes(16)),
'session_id' => bin2hex(random_bytes(16)),
'properties' => $properties,
'timestamp' => gmdate('Y-m-d\TH:i:s.v\Z'),
]);
$ch = curl_init($endpoint);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $payload,
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 5,
]);
curl_exec($ch);
curl_close($ch);
}
// Track user login
function zenovay_track_login($user_login, $user)
{
$trackingCode = getenv('ZENOVAY_TRACKING_CODE');
if (!$trackingCode) return;
$endpoint = "https://api.zenovay.com/e/{$trackingCode}";
// Send identify event
$identifyPayload = json_encode([
'event_type' => 'identify',
'event_name' => 'user_identified',
'user_profile' => [
'user_id' => (string) $user->ID,
'email' => $user->user_email,
'name' => $user->display_name,
'role' => implode(', ', $user->roles),
],
'url' => home_url('/wp-login.php'),
'visitor_id' => bin2hex(random_bytes(16)),
'session_id' => bin2hex(random_bytes(16)),
'timestamp' => gmdate('Y-m-d\TH:i:s.v\Z'),
]);
$ch = curl_init($endpoint);
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => $identifyPayload,
CURLOPT_HTTPHEADER => ['Content-Type: application/json'],
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 5,
]);
curl_exec($ch);
curl_close($ch);
// Send login event
zenovay_send_event('user_logged_in', [
'method' => 'wordpress',
'user_id' => (string) $user->ID,
]);
}
add_action('wp_login', 'zenovay_track_login', 10, 2);
?>
Complete Example
Here's a complete PHP application with Zenovay:
<?php
// index.php
require __DIR__ . '/config/analytics.php';
session_start();
// Identify logged-in user
if (isset($_SESSION['user_id'])) {
$user = getUserById($_SESSION['user_id']);
if ($user) {
zenovay_identify(
(string) $user['id'],
$user['email'],
'https://yoursite.com' . $_SERVER['REQUEST_URI'],
null,
null,
['name' => $user['name']]
);
}
}
// Track page view
zenovay_track(
'page_viewed',
'https://yoursite.com' . $_SERVER['REQUEST_URI'],
null,
null,
[
'page' => $_SERVER['REQUEST_URI'],
'referrer' => $_SERVER['HTTP_REFERER'] ?? null,
]
);
// Your application code
?>
<!DOCTYPE html>
<html>
<head>
<title>My PHP App</title>
<script src="https://api.zenovay.com/z.js"
data-tracking-code="<?php echo htmlspecialchars(getenv('ZENOVAY_TRACKING_CODE')); ?>"
async></script>
</head>
<body>
<h1>Welcome to My App</h1>
</body>
</html>
Testing
Mock the tracking calls in your PHPUnit tests:
<?php
// tests/SignupTest.php
use PHPUnit\Framework\TestCase;
class SignupTest extends TestCase
{
public function testSignupTracksEvent()
{
// Verify the correct payload structure is built
$payload = [
'event_type' => 'custom',
'event_name' => 'signup_completed',
'url' => 'https://yoursite.com/signup',
'visitor_id' => 'test-visitor-id',
'session_id' => 'test-session-id',
'properties' => ['plan' => 'pro', 'user_id' => '123'],
'timestamp' => '2026-02-27T12:00:00.000Z',
];
$this->assertEquals('signup_completed', $payload['event_name']);
$this->assertEquals('pro', $payload['properties']['plan']);
}
}
?>
Tracking Endpoint Reference
All server-side events are sent as POST requests to:
https://api.zenovay.com/e/YOUR_TRACKING_CODE
Custom Event Payload
{
"event_type": "custom",
"event_name": "event_name_here",
"url": "https://yoursite.com/page",
"visitor_id": "unique-visitor-id",
"session_id": "unique-session-id",
"properties": { "key": "value" },
"timestamp": "2026-02-27T12:00:00.000Z"
}
Identify Event Payload
{
"event_type": "identify",
"event_name": "user_identified",
"user_profile": { "user_id": "123", "email": "[email protected]" },
"url": "https://yoursite.com",
"visitor_id": "unique-visitor-id",
"session_id": "unique-session-id",
"timestamp": "2026-02-27T12:00:00.000Z"
}
Next Steps
- API Reference - Full API documentation
- Custom Events - Learn about event tracking
- Privacy Compliance - GDPR and CCPA setup
- Dashboard Overview - Understand your data
Getting Help
- Documentation: docs.zenovay.com
- Support: [email protected]