Back to Screenpipe

pipe permissions

docs/mintlify/docs-mintlify-mig-tmp/pipe-permissions.mdx

2.3.276.4 KB
Original Source

overview

pipes can access the screenpipe API to read screen data, manage meetings, send notifications, and more. by default, pipes have full access to every endpoint — no restrictions.

if you want to limit what a pipe can do, add a permissions block to the YAML frontmatter in pipe.md. this is useful for:

  • preventing accidents — a pipe that reads meetings shouldn't be able to stop one
  • least privilege — pipes from the store should only access what they need
  • safety — deny destructive endpoints like /data/delete-range

quick start

yaml
---
schedule: every 30m
permissions: reader
---

Summarize my screen activity...

that's it. this pipe can only read data — it can't start/stop meetings, delete data, or run raw SQL.

presets

reader — safe read-only defaults

yaml
permissions: reader

allowed endpoints:

methodendpointdescription
GET/searchquery screen/audio data
GET/activity-summaryapp usage overview
GET/elementsUI element search
GET/frames/*screenshots (if allow_frames: true)
GET/meetingslist meetings
GET/meetings/*get meeting details
GET/meetings/statuscheck if in meeting
POST/notifysend notifications
GET/speakerslist speakers
POST/speakers/updateupdate speaker names
GET/pipes/infopipe metadata
GET/healthhealth check
GET/connections/*connection credentials

everything else is denied.

writer — reader + write operations

yaml
permissions: writer

includes all reader endpoints, plus:

methodendpointdescription
POST/meetings/startstart a manual meeting
POST/meetings/stopstop a manual meeting
PUT/meetings/*update meeting details
POST/meetings/mergemerge meetings
POST/memoriescreate memories
PUT/memories/*update memories
DELETE/memories/*delete memories

admin — full access (explicit)

yaml
permissions: admin

allows everything. functionally the same as no permissions block, but creates a token for logging/auditing.

custom rules

for fine-grained control, use allow and deny lists with Api(METHOD /path) patterns:

yaml
permissions:
  allow:
    - Api(GET /search)
    - Api(GET /meetings/*)
    - Api(POST /notify)
  deny:
    - Api(* /data/delete-*)

pattern syntax

patternmatches
Api(GET /search)exact: GET to /search
Api(GET /meetings/*)glob: GET to /meetings/42, /meetings/status, etc.
Api(* /meetings/stop)any method to /meetings/stop
Api(POST /notify)exact: POST to /notify
Api(* /data/*)any method to any /data/ subpath

* in the method position matches GET, POST, PUT, DELETE, etc. * in the path position matches any sequence of characters.

evaluation order

rules are evaluated in this order — first match wins:

  1. deny — if the request matches any deny rule, it's blocked (403)
  2. allow — if the request matches any allow rule, it passes
  3. default allowlist — if allow is empty and the pipe uses a preset with defaults (reader/writer), the default list is checked
  4. reject — if nothing matched, the request is blocked

deny always wins over allow, just like firewall rules.

examples

deny specific endpoints (keep full access otherwise):

yaml
permissions:
  deny:
    - Api(* /meetings/stop)
    - Api(* /meetings/start)
    - Api(DELETE /meetings/*)
    - Api(* /data/delete-*)

allow only what you need (everything else denied):

yaml
permissions:
  allow:
    - Api(GET /search)
    - Api(POST /notify)

reader defaults + custom deny:

yaml
permissions:
  deny:
    - Api(GET /frames/*)

this uses the reader defaults but also blocks screenshot access.

data access rules

data filtering uses the same allow/deny lists with App(), Window(), and Content() rules:

yaml
---
schedule: every 1h
permissions:
  allow:
    - Api(GET /search)
    - App(Slack, Chrome)
    - Window(*meeting*)
    - Content(ocr, audio)
  deny:
    - App(1Password, Signal)
    - Window(*incognito*, *bank*)
    - Content(input)
  time: "09:00-17:00"
  days: "Mon,Tue,Wed,Thu,Fri"
---
rule typesyntaxdescription
App(name)App(Slack) or App(Slack, Chrome)filter by app name (case-insensitive substring match)
Window(glob)Window(*meeting*)filter by window title (glob pattern)
Content(type)Content(ocr, audio)filter content types: ocr, audio, input, accessibility
time"09:00-17:00"daily time window — supports midnight wrap ("22:00-06:00")
days"Mon,Tue,Wed,Thu,Fri"allowed days of the week

deny rules always win over allow rules. if no rules of a given type exist, everything is allowed.

how it works

when a pipe has any restrictions (permissions block, data filters, etc.):

  1. screenpipe generates a unique token (sp_pipe_*) for the pipe session
  2. the token is registered with the server middleware
  3. every API request from the pipe includes the token in Authorization: Bearer sp_pipe_*
  4. the middleware checks is_endpoint_allowed(method, path) before forwarding
  5. the Pi extension also enforces rules client-side (blocks curl commands before they run)
  6. when the pipe finishes, the token is cleaned up

pipes without any restrictions run without a token — full access, zero overhead.

common recipes

meeting-safe pipe

your pipe reads meeting data but should never interfere with active meetings:

yaml
---
schedule: every 1h
permissions:
  deny:
    - Api(* /meetings/start)
    - Api(* /meetings/stop)
    - Api(POST /meetings/merge)
    - Api(POST /meetings/bulk-delete)
    - Api(DELETE /meetings/*)
---

Summarize my meetings from the last hour...

read-only analytics pipe

yaml
---
schedule: daily
permissions:
  allow:
    - Api(GET /search)
    - App(Chrome, Arc, Firefox)
    - Content(ocr)
---

Generate a daily browsing report...

work-hours-only pipe

yaml
---
schedule: every 30m
permissions:
  time: "09:00-17:00"
  days: "Mon,Tue,Wed,Thu,Fri"
---

Track my work activity...

full API access, but time and day restrictions limit when data is visible.

need help? ask in our discord