blob: 756ecb6932aa8b1df6dddadfcf3bb06c1e4c87c3 [file] [log] [blame] [view] [edit]
# 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](/docs/visualization/extension-servers.md).
## 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.
```json
{
"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"}`.
```json
{
"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](/docs/visualization/commands-automation-reference.md)
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"}`.
```json
{
"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"}`.
```json
{
"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-Type
```
If 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.com` to 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_modules
```
Serve 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)
```python
from flask import Flask, jsonify
app = Flask(__name__)
@app.route('/manifest')
def manifest():
return jsonify({
"name": "My Extensions",
"namespace": "com.example",
"features": [{"name": "macros"}, {"name": "sql_modules"}],
"modules": [{"id": "default", "name": "Default"}],
})
@app.route('/modules/<module>/macros')
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"]
}
]
}
]
})
@app.route('/modules/<module>/sql_modules')
def sql_modules(module):
return jsonify({
"sql_modules": [
{"name": "com.example.helpers", "sql": "CREATE PERFETTO TABLE ...;"}
]
})
@app.after_request
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 response
```
## See also
- [Extension Server Setup Guide](/docs/visualization/extension-servers.md) —
Step-by-step setup using the GitHub template
- [Extension Servers](/docs/visualization/extension-servers.md) —
What extension servers are and how they work
- [Commands Automation Reference](/docs/visualization/commands-automation-reference.md) —
Available command IDs for macros