Reserved Collections
pb-ext creates the following PocketBase system collections automatically on startup. Do not create collections with these names in your own code.
Creating collections with these reserved names will cause conflicts and may break pb-ext functionality.
Collections Table
Collection Purpose _analyticsDaily aggregated page view counters (one row per path/date/device/browser). Retention: 90 days. _analytics_sessionsRing buffer of the 50 most recent visits for the Recent Activity display. No PII stored. _job_logsCron job execution logs (start time, end time, duration, status, output). Retention: 72 hours.
_analytics
Purpose : Stores daily aggregated visitor analytics data.
Type : System collection (hidden from PocketBase Collections UI)
Retention : Automatically purged after 90 days
Schema
Field Type Description pathstring Page path (e.g., /api/v1/todos) datedate Aggregation date (day-level) devicestring Device category: desktop, mobile, tablet, or unknown browserstring Browser family: Chrome, Firefox, Safari, etc. viewsinteger Total page views for this combination unique_visitorsinteger Estimated unique visitors (deduplicated by session)
GDPR Compliance
No PII stored :
No IP addresses
No user agents
No visitor IDs
No session tokens
Only aggregated counts by device/browser category.
Example Query
records , err := app . FindRecordsByFilter (
"_analytics" ,
"date >= {:today}" ,
"-views" ,
100 ,
0 ,
dbx . Params { "today" : time . Now (). Format ( "2006-01-02" )},
)
_analytics_sessions
Purpose : Ring buffer of the 50 most recent visitor sessions for the “Recent Activity” dashboard widget.
Type : System collection (hidden from PocketBase Collections UI)
Retention : Only the 50 most recent records are kept (ring buffer)
Schema
Field Type Description timestampdatetime Visit timestamp pathstring Visited page path devicestring Device category browserstring Browser family referrerstring Referrer URL (sanitized, no query params) utm_sourcestring UTM source parameter utm_mediumstring UTM medium parameter utm_campaignstring UTM campaign parameter
GDPR Compliance
No PII stored :
No IP addresses
No user agents
No cookies
No fingerprinting
Ring Buffer Behavior
When the 51st record is inserted:
Oldest record is deleted
New record is inserted
Collection always contains ≤ 50 records
_job_logs
Purpose : Stores cron job execution logs.
Type : System collection (hidden from PocketBase Collections UI)
Retention : Automatically purged after 72 hours
Schema
Field Type Description job_idstring Unique job identifier job_namestring Human-readable job name start_timedatetime Execution start timestamp end_timedatetime Execution end timestamp duration_msinteger Execution duration in milliseconds statusstring success, failed, or runningoutputtext Structured JSON log output errortext Error message if status is failed progressinteger Progress percentage (0-100) statisticsjson Custom job statistics (optional)
Example Query
// Get logs for specific job
records , err := app . FindRecordsByFilter (
"_job_logs" ,
"job_id = {:jobId}" ,
"-start_time" ,
50 ,
0 ,
dbx . Params { "jobId" : "myCustomJob" },
)
// Get failed jobs from last 24 hours
records , err := app . FindRecordsByFilter (
"_job_logs" ,
"status = 'failed' && start_time >= {:since}" ,
"-start_time" ,
100 ,
0 ,
dbx . Params { "since" : time . Now (). Add ( - 24 * time . Hour )},
)
System Jobs
pb-ext registers these system jobs automatically:
Job ID Schedule Description __pbExtLogClean__0 0 * * * (daily midnight)Purge _job_logs records older than 72 hours __pbExtAnalyticsClean__0 3 * * * (daily 3 AM)Purge _analytics rows older than 90 days
They appear in the dashboard with the “System” badge.
Auto-Migration on Upgrade
Schema notes :
All three collections are system collections (hidden from the PocketBase Collections UI)
On upgrade from an old pb-ext version, incompatible schemas are automatically migrated at startup
No manual steps required
Migration Process
pb-ext checks if collection exists
If exists, validates schema matches expected
If schema mismatch, runs migration
If doesn’t exist, creates with correct schema
Logs
Migration logs appear in server output:
[INFO] pb-ext: migrating _analytics collection schema
[INFO] pb-ext: _job_logs collection created
[INFO] pb-ext: all system collections ready
Accessing Collections Programmatically
Read Analytics Data
package main
import (
" github.com/pocketbase/pocketbase/core "
)
func getTopPages ( app core . App ) ([] * core . Record , error ) {
return app . FindRecordsByFilter (
"_analytics" ,
"date >= {:week_ago}" ,
"-views" ,
10 ,
0 ,
dbx . Params {
"week_ago" : time . Now (). AddDate ( 0 , 0 , - 7 ). Format ( "2006-01-02" ),
},
)
}
Read Job Logs
func getJobHistory ( app core . App , jobID string ) ([] * core . Record , error ) {
return app . FindRecordsByFilter (
"_job_logs" ,
"job_id = {:id}" ,
"-start_time" ,
20 ,
0 ,
dbx . Params { "id" : jobID },
)
}
Do not manually create, update, or delete records in these collections. Use pb-ext’s provided APIs instead.
Dashboard Integration
pb-ext’s dashboard at /_/_ visualizes data from these collections:
Analytics Tab :
Page view charts (from _analytics)
Device breakdown
Browser distribution
Recent activity feed (from _analytics_sessions)
Jobs Tab :
Registered cron jobs
Execution history (from _job_logs)
Job status monitoring
Manual job triggers
Customizing Retention
Retention is controlled by the system cleanup jobs. To customize:
Analytics Retention (default: 90 days)
// Unregister default cleanup job
server . GetJobManager (). RemoveJob ( "__pbExtAnalyticsClean__" )
// Register custom cleanup with different retention
server . GetJobManager (). RegisterJob (
"customAnalyticsClean" ,
"Custom Analytics Cleanup" ,
"Clean analytics older than 180 days" ,
"0 3 * * *" , // daily at 3 AM
func ( logger * server . JobExecutionLogger ) {
logger . Start ()
cutoff := time . Now (). AddDate ( 0 , 0 , - 180 ) // 180 days
_ , err := app . Delete ( "_analytics" , "date < {:cutoff}" , dbx . Params { "cutoff" : cutoff })
if err != nil {
logger . Fail ( err . Error ())
} else {
logger . Success ( "Analytics cleaned" )
}
},
)
Job Logs Retention (default: 72 hours)
server . GetJobManager (). RemoveJob ( "__pbExtLogClean__" )
server . GetJobManager (). RegisterJob (
"customLogClean" ,
"Custom Log Cleanup" ,
"Clean job logs older than 7 days" ,
"0 0 * * *" ,
func ( logger * server . JobExecutionLogger ) {
logger . Start ()
cutoff := time . Now (). AddDate ( 0 , 0 , - 7 ) // 7 days
_ , err := app . Delete ( "_job_logs" , "start_time < {:cutoff}" , dbx . Params { "cutoff" : cutoff })
if err != nil {
logger . Fail ( err . Error ())
} else {
logger . Success ( "Logs cleaned" )
}
},
)
Best Practices
Don't Create These Collections Never manually create collections with reserved names. Let pb-ext handle initialization.
Read-Only Access Treat these as read-only from your application code. Write operations should go through pb-ext APIs.
Monitor Disk Usage If analytics volume is high, consider shorter retention periods or archival strategies.
Backup Carefully These collections change frequently. Exclude from backups or use incremental strategies.
Further Reading