Accept text/plain events from the Plausible tracker
dependabot-auto-merge / dependabot (pull_request_target) Skipped
Fix PHP code style issues / php-code-styling (push) Successful in 6s
PHPStan / phpstan (push) Successful in 2m38s
run-tests / P8.3 - L11.* - prefer-lowest - ubuntu-latest (push) Failing after 33s
run-tests / P8.4 - L11.* - prefer-lowest - ubuntu-latest (push) Canceled after 0s
run-tests / P8.4 - L11.* - prefer-stable - ubuntu-latest (push) Canceled after 0s
run-tests / P8.3 - L12.* - prefer-lowest - ubuntu-latest (push) Canceled after 0s
run-tests / P8.3 - L12.* - prefer-stable - ubuntu-latest (push) Canceled after 0s
run-tests / P8.4 - L12.* - prefer-lowest - ubuntu-latest (push) Canceled after 0s
run-tests / P8.4 - L12.* - prefer-stable - ubuntu-latest (push) Canceled after 0s
run-tests / P8.3 - L13.* - prefer-lowest - ubuntu-latest (push) Canceled after 0s
run-tests / P8.3 - L13.* - prefer-stable - ubuntu-latest (push) Canceled after 0s
run-tests / P8.4 - L13.* - prefer-lowest - ubuntu-latest (push) Canceled after 0s
run-tests / P8.4 - L13.* - prefer-stable - ubuntu-latest (push) Canceled after 0s
run-tests / P8.3 - L11.* - prefer-stable - ubuntu-latest (push) Canceled after 1s

The Plausible tracker posts its JSON payload with Content-Type text/plain,
  which Laravel does not parse, so every real event failed validation and
  was redirected instead of being forwarded.

  - Decode the raw body when the request is not JSON
  - Respond with 400 instead of a redirect on invalid non-JSON requests
  - Trim trailing slash from the configured domain when forwarding events
  - Add a 5s timeout and respond with 502 when Plausible is unreachable
This commit is contained in:
mathiaspalmqvist committed 2026-11-12 09:18:50 +01:00
1 parent c1338fad8b
commit a97baf5921
3 files changed
+98 -4

No files matched your search

@@ -2,18 +2,30 @@
namespace Mattitja\LaravelPlausibleProxy\Http\Controllers;
use Illuminate\Http\Client\ConnectionException;
use Illuminate\Http\Response;
use Illuminate\Support\Facades\Http;
use Illuminate\Support\Facades\Log;
use Mattitja\LaravelPlausibleProxy\Http\Requests\PlausibleEventRequest;
class PlausibleEventApiController
{
public function __invoke(PlausibleEventRequest $request): Response
{
$upstream = Http::withHeaders([
'User-Agent' => (string) $request->userAgent(),
'X-Forwarded-For' => (string) $request->ip(),
])->post(config('plausible-proxy.domain').'/api/event', $request->all());
$url = rtrim((string) config('plausible-proxy.domain'), '/').'/api/event';
try {
$upstream = Http::timeout(5)
->withHeaders([
'User-Agent' => (string) $request->userAgent(),
'X-Forwarded-For' => (string) $request->ip(),
])
->post($url, $request->all());
} catch (ConnectionException $e) {
Log::error('Failed to forward Plausible event: '.$e->getMessage());
return response('Bad Gateway', 502);
}
return response($upstream->body(), $upstream->status())
->header('Content-Type', $upstream->header('Content-Type') ?: 'text/plain');