Extension Server Protocol Reference
This page documents the HTTP protocol that extension servers must implement. Use this if you are building a custom extension server rather than using the GitHub template approach.
Endpoints
Extension servers implement these HTTP(S) endpoints:
{base_url}/manifest GET (required)
{base_url}/modules/{module_id}/macros GET (optional)
{base_url}/modules/{module_id}/sql_modules GET (optional)
{base_url}/modules/{module_id}/proto_descriptors GET (optional)The UI only fetches optional endpoints for features declared in the manifest.
Manifest
Endpoint: GET {base_url}/manifest
Returns server metadata, supported features, and available modules.
{
"name": "Acme Corp Extensions",
"namespace": "com.acme",
"features": [
{"name": "macros"},
{"name": "sql_modules"},
{"name": "proto_descriptors"}
],
"modules": [
{"id": "default", "name": "Default"},
{"id": "android", "name": "Android"},
{"id": "chrome", "name": "Chrome"}
]
}Fields
| Field | Type | Required | Description |
|---|---|---|---|
name |
string | Yes | Human-readable server name, shown in Settings and command palette source chips. |
namespace |
string | Yes | Unique identifier in reverse-domain notation (e.g., com.acme). Used to enforce naming constraints on macros and SQL modules. |
features |
array | Yes | Features this server supports. Each entry has a name field. Valid names: macros, sql_modules, proto_descriptors. |
modules |
array | Yes | Available modules. Each entry has an id (used in URL paths and settings) and a name (human-readable display name). |
For single-module servers, use [{"id": "default", "name": "Default"}].
Macros
Endpoint: GET {base_url}/modules/{module_id}/macros
Only fetched if features includes {"name": "macros"}.
{
"macros": [
{
"id": "com.acme.StartupAnalysis",
"name": "Startup Analysis",
"run": [
{"id": "dev.perfetto.RunQuery", "args": ["SELECT 1"]},
{"id": "dev.perfetto.PinTracksByRegex", "args": [".*CPU.*"]}
]
}
]
}Macro fields
| Field | Type | Description |
|---|---|---|
id |
string | Unique identifier. Must start with the server's namespace followed by . (e.g., com.acme.StartupAnalysis). |
name |
string | Display name shown in the command palette. |
run |
array | Commands to execute in sequence. Each entry has a command id and an args array. |
See the Commands Automation Reference for the full list of available command IDs and their arguments.
SQL modules
Endpoint: GET {base_url}/modules/{module_id}/sql_modules
Only fetched if features includes {"name": "sql_modules"}.
{
"sql_modules": [
{
"name": "com.acme.startup",
"sql": "CREATE PERFETTO TABLE _startup_events AS SELECT ts, dur, name FROM slice WHERE name GLOB 'startup*';"
},
{
"name": "com.acme.memory",
"sql": "CREATE PERFETTO FUNCTION com_acme_rss_mb(upid INT) RETURNS FLOAT AS SELECT CAST(value AS FLOAT) / 1048576 FROM counter WHERE track_id IN (SELECT id FROM process_counter_track WHERE upid = $upid AND name = 'mem.rss') ORDER BY ts DESC LIMIT 1;"
}
]
}SQL module fields
| Field | Type | Description |
|---|---|---|
name |
string | Module name. Must start with the server's namespace followed by . (e.g., com.acme.startup). Users reference this with INCLUDE PERFETTO MODULE com.acme.startup;. |
sql |
string | SQL text. Can contain CREATE PERFETTO TABLE, CREATE PERFETTO FUNCTION, CREATE PERFETTO VIEW, or any valid PerfettoSQL. |
Proto descriptors
Endpoint: GET {base_url}/modules/{module_id}/proto_descriptors
Only fetched if features includes {"name": "proto_descriptors"}.
{
"proto_descriptors": [
"CgdteV9wcm90bxIHbXlwcm90byI...",
"Cghhbm90aGVyEghhbm90aGVyIi..."
]
}Proto descriptor fields
| Field | Type | Description |
|---|---|---|
proto_descriptors |
array of strings | Base64-encoded FileDescriptorSet protocol buffer messages. These allow the UI to decode custom protobuf messages in traces. |
Proto descriptors are not subject to namespace enforcement since protobuf messages have their own package-based namespacing.
Namespace enforcement
All macro IDs and SQL module names must start with the server's namespace
value from the manifest, followed by a .. For example, a server with namespace
com.acme can only serve:
- Macro IDs like
com.acme.StartupAnalysis,com.acme.MemoryCheck - SQL module names like
com.acme.startup,com.acme.memory.helpers
The UI validates this and rejects extensions that violate the convention. This prevents naming conflicts when users configure multiple extension servers.
CORS requirements
All HTTPS extension servers must set CORS headers to allow the Perfetto UI to make cross-origin requests:
Access-Control-Allow-Origin: https://ui.perfetto.dev
Access-Control-Allow-Methods: GET
Access-Control-Allow-Headers: Authorization, Content-TypeIf your server supports multiple Perfetto UI deployments, you can reflect the
Origin request header instead of hardcoding a single origin.
GitHub-hosted servers do not need CORS configuration —
raw.githubusercontent.com and the GitHub API already set appropriate headers.
CORS failures appear as network errors in the browser console. The affected server is skipped and other servers continue to load normally.
Authentication headers
The Perfetto UI constructs authentication headers based on the server's configured auth type:
| Auth type | Header |
|---|---|
none |
No auth headers |
github_pat |
Authorization: token <pat> (via GitHub API) |
https_basic |
Authorization: Basic <base64(username:password)> |
https_apikey (bearer) |
Authorization: Bearer <key> |
https_apikey (x_api_key) |
X-API-Key: <key> |
https_apikey (custom) |
<custom_header_name>: <key> |
https_sso |
No header; request sent with credentials: 'include' |
For SSO authentication, if a request returns HTTP 403, the UI loads the server's base URL in a hidden iframe to refresh the SSO session cookie, then retries the request once.
GitHub server URL construction
For GitHub-hosted extension servers, the UI constructs fetch URLs automatically:
- Unauthenticated (public repos): Uses
raw.githubusercontent.comto avoid GitHub API rate limits.https://raw.githubusercontent.com/{repo}/{ref}/{path}/manifest - Authenticated (private repos): Uses the GitHub Contents API.
https://api.github.com/repos/{repo}/contents/{path}/manifest?ref={ref}With header:Accept: application/vnd.github.raw+json
Example: minimal static server
A complete extension server can be a set of static JSON files:
my-extensions/
manifest
modules/
default/
macros
sql_modulesServe these with any static file server (nginx, Caddy, GCS, S3) that sets the required CORS headers. No dynamic server logic is needed for basic use cases.
Example: dynamic server (Python/Flask)
from flask import Flask, jsonify
app = Flask(__name__)
def manifest():
return jsonify({
"name": "My Extensions",
"namespace": "com.example",
"features": [{"name": "macros"}, {"name": "sql_modules"}],
"modules": [{"id": "default", "name": "Default"}],
})
def macros(module):
return jsonify({
"macros": [
{
"id": "com.example.ShowLongSlices",
"name": "Show Long Slices",
"run": [
{
"id": "dev.perfetto.RunQueryAndShowTab",
"args": ["SELECT * FROM slice ORDER BY dur DESC LIMIT 20"]
}
]
}
]
})
def sql_modules(module):
return jsonify({
"sql_modules": [
{"name": "com.example.helpers", "sql": "CREATE PERFETTO TABLE ...;"}
]
})
def add_cors(response):
response.headers['Access-Control-Allow-Origin'] = 'https://ui.perfetto.dev'
response.headers['Access-Control-Allow-Methods'] = 'GET'
response.headers['Access-Control-Allow-Headers'] = 'Authorization, Content-Type'
return responseSee also
- Extension Server Setup Guide — Step-by-step setup using the GitHub template
- Extension Servers — What extension servers are and how they work
- Commands Automation Reference — Available command IDs for macros