Laravel Proxy Setup
Configure Laravel routes and middleware to proxy AddonPulse tracking
Laravel makes it straightforward to proxy AddonPulse tracking using routes and the HTTP client. This guide shows how to set up proxy endpoints in your Laravel application.
Overview
Laravel's HTTP client (built on Guzzle) provides an elegant way to proxy requests to AddonPulse servers while maintaining full control over headers, caching, and error handling.
What you'll achieve:
- Proxy all AddonPulse endpoints through your Laravel app
- Forward necessary headers for accurate tracking
- Optional caching with Laravel Cache
- Support all AddonPulse features
Prerequisites
- Laravel 8 or later
- Your AddonPulse instance URL
https://app.addonpulse.com - Your AddonPulse site ID
Implementation
Configure Environment Variables
Add your AddonPulse host to .env:
# .env
ADDONPULSE_HOST=https://app.addonpulse.comCreate Analytics Controller
Generate a controller for handling analytics proxying:
php artisan make:controller AnalyticsProxyControllerThen implement the proxy logic:
<?php
// app/Http/Controllers/AnalyticsProxyController.php
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Cache;
class AnalyticsProxyController extends Controller
{
private string $addonpulseHost;
public function __construct()
{
$this->addonpulseHost = config('services.addonpulse.host', 'https://app.addonpulse.com');
}
/**
* Proxy script requests (GET)
*/
public function proxyScript(Request $request, string $script)
{
// Cache scripts for 1 hour
$cacheKey = "addonpulse_script_{$script}";
return Cache::remember($cacheKey, 3600, function () use ($script, $request) {
return $this->forwardRequest("api/{$script}", 'GET', $request);
});
}
/**
* Proxy tracking requests (POST)
*/
public function proxyTrack(Request $request)
{
return $this->forwardRequest('api/track', 'POST', $request);
}
/**
* Proxy identify requests (POST)
*/
public function proxyIdentify(Request $request)
{
return $this->forwardRequest('api/identify', 'POST', $request);
}
/**
* Proxy site configuration (GET)
*/
public function proxySiteConfig(Request $request, string $siteId)
{
// Cache config for 5 minutes
$cacheKey = "addonpulse_config_{$siteId}";
return Cache::remember($cacheKey, 300, function () use ($siteId, $request) {
return $this->forwardRequest("api/site/tracking-config/{$siteId}", 'GET', $request);
});
}
/**
* Forward request to AddonPulse backend
*/
private function forwardRequest(string $path, string $method, Request $request)
{
$url = "{$this->addonpulseHost}/{$path}";
// Get client IP
$clientIp = $request->header('X-Forwarded-For', $request->ip());
// Build HTTP request
$httpRequest = Http::timeout(30)
->withHeaders([
'X-Real-IP' => $clientIp,
'X-Forwarded-For' => $clientIp,
'User-Agent' => $request->header('User-Agent'),
'Referer' => $request->header('Referer', ''),
]);
try {
if ($method === 'POST') {
$response = $httpRequest->post($url, $request->all());
} else {
$response = $httpRequest->get($url);
}
return response($response->body(), $response->status())
->header('Content-Type', $response->header('Content-Type'));
} catch (\Exception $e) {
\Log::error('AddonPulse proxy error', [
'url' => $url,
'error' => $e->getMessage(),
]);
return response()->json(['error' => 'Analytics proxy error'], 500);
}
}
}Add Routes
Add routes for the analytics proxy in routes/web.php:
<?php
// routes/web.php
use App\Http\Controllers\AnalyticsProxyController;
// Analytics proxy routes
Route::prefix('analytics')->group(function () {
// Scripts (GET)
Route::get('/{script}', [AnalyticsProxyController::class, 'proxyScript'])
->where('script', '(script|replay|metrics)\.js');
// Tracking endpoints (POST)
Route::post('/track', [AnalyticsProxyController::class, 'proxyTrack']);
Route::post('/identify', [AnalyticsProxyController::class, 'proxyIdentify']);
// Configuration (GET)
Route::get('/site/tracking-config/{siteId}', [AnalyticsProxyController::class, 'proxySiteConfig']);
});Add Service Configuration (Optional)
Add AddonPulse configuration to config/services.php:
<?php
// config/services.php
return [
// ... other services
'addonpulse' => [
'host' => env('ADDONPULSE_HOST', 'https://app.addonpulse.com'),
],
];Update Your Blade Templates
Add the tracking script to your layout:
{{-- resources/views/layouts/app.blade.php --}}
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>{{ config('app.name') }}</title>
{{-- AddonPulse Analytics --}}
<script src="{{ url('/analytics/script.js') }}" async data-site-id="YOUR_SITE_ID"></script>
</head>
<body>
@yield('content')
</body>
</html>Verify the Setup
-
Clear route cache (if caching enabled):
php artisan route:clear -
Visit your application with Developer Tools open
-
Check Network tab: Requests should go to
/analytics/* -
Verify in AddonPulse dashboard: Data should appear
How It Works
Laravel routes intercept requests to /analytics/* and forward them to AddonPulse:
- Request to
/analytics/script.jshits Laravel route - Controller forwards to
https://app.addonpulse.com/api/script.js - Response is cached (for cacheable endpoints)
- Client IP and headers are preserved for accurate tracking
Advanced Configuration
Middleware for Rate Limiting
Create rate limiting middleware:
php artisan make:middleware RateLimitAnalytics<?php
// app/Http/Middleware/RateLimitAnalytics.php
namespace App\Http\Middleware;
use Closure;
use Illuminate\Cache\RateLimiter;
class RateLimitAnalytics
{
protected $limiter;
public function __construct(RateLimiter $limiter)
{
$this->limiter = $limiter;
}
public function handle($request, Closure $next)
{
$key = 'analytics:' . $request->ip();
if ($this->limiter->tooManyAttempts($key, 100)) {
return response('Too Many Requests', 429);
}
$this->limiter->hit($key, 60); // 100 requests per minute
return $next($request);
}
}Register in app/Http/Kernel.php:
protected $routeMiddleware = [
// ... other middleware
'rate.limit.analytics' => \App\Http\Middleware\RateLimitAnalytics::class,
];Apply to routes:
Route::prefix('analytics')->middleware('rate.limit.analytics')->group(function () {
// ... routes
});Custom Cache Configuration
Use different cache drivers for analytics:
private function forwardRequest(string $path, string $method, Request $request)
{
// Use Redis for analytics caching
$cache = Cache::store('redis');
// Or use file cache
// $cache = Cache::store('file');
// ... rest of the method
}CORS Configuration
If serving from a different domain:
<?php
// config/cors.php
return [
'paths' => ['analytics/*'],
'allowed_methods' => ['GET', 'POST'],
'allowed_origins' => ['https://yourdomain.com'],
'allowed_headers' => ['Content-Type', 'X-Requested-With'],
];Troubleshooting
404 Not Found
Problem: Routes return 404.
Solution:
- Clear route cache:
php artisan route:clear - List routes to verify:
php artisan route:list --path=analytics - Check route order (more specific routes first)
Session errors with POST requests
Problem: CSRF token errors on tracking endpoints.
Solution:
Exclude analytics routes from CSRF protection in app/Http/Middleware/VerifyCsrfToken.php:
protected $except = [
'analytics/*',
];Incorrect geolocation
Problem: All visitors show server's location.
Solution: Ensure IP forwarding in controller:
$clientIp = $request->header('X-Forwarded-For', $request->ip());And add to HTTP request:
'X-Real-IP' => $clientIp,
'X-Forwarded-For' => $clientIp,Cache not clearing
Problem: Old script cached after AddonPulse update.
Solution: Clear specific cache key:
php artisan cache:forget addonpulse_script_script.jsOr clear all cache:
php artisan cache:clearPerformance Optimization
Cache Optimization
// Configure cache tags for easy clearing
Cache::tags(['addonpulse', 'scripts'])->remember($cacheKey, 3600, function () {
// ... fetch script
});
// Clear all AddonPulse cache
Cache::tags(['addonpulse'])->flush();HTTP Client Optimization
// Use connection pooling
Http::pool(fn (Pool $pool) => [
$pool->get("{$this->addonpulseHost}/api/script.js"),
$pool->get("{$this->addonpulseHost}/api/replay.js"),
]);Related Resources
- Laravel Integration Guide - General Laravel integration
- Tracking Script Documentation - Script configuration
- Laravel HTTP Client - Official Laravel docs