Exposure Profiles
Exposure Profiles define what data a user shares with apps. They're the key to user-controlled privacy.
What is an Exposure Profile?
An exposure profile is a set of rules that specify:
- What types of nodes are accessible
- Which tags are included or excluded
- What permissions are granted (read, write, delete)
Think of it as a privacy filter between user data and third-party apps.
How It Works
┌────────────────────────────────────────────────────── ───────────┐
│ USER'S DATA VAULT │
│ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ All Data: Notes, Files, Contacts, Personal, Health... │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │ │
│ Exposure Profile Filter │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ Filtered: Only Work notes, Only tag "public" │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘
│
▼
┌─────────────────┐
│ Third-Party │
│ App │
└─────────────────┘
Profile Structure
{
"id": "profile_work123",
"name": "Work Data Only",
"description": "Share only work-related notes and documents",
"owner_id": "user_123",
"scope": {
"node_types": ["note", "document"],
"tag_ids": ["tag_work", "tag_projects"],
"exclude_tag_ids": ["tag_private", "tag_personal"],
"permissions": ["read"]
},
"is_default": false,
"created_at": "2024-01-15T10:30:00Z"
}
Scope Options
| Field | Type | Description |
|---|---|---|
node_types | array | Only these node types are visible |
tag_ids | array | Only nodes with these tags |
exclude_tag_ids | array | Exclude nodes with these tags |
permissions | array | read, write, delete |
Permission Levels
| Permission | Allows |
|---|---|
read | View nodes, list, search |
write | Create new nodes, update existing |
delete | Remove nodes |
Working with Exposure Profiles
Create a Profile
profile = client.exposure_profiles.create(
user_id="user-123",
name="Work Data Only",
description="Share work notes and documents",
scope={
"node_types": ["note", "document"],
"tag_ids": ["tag_work"],
"exclude_tag_ids": ["tag_private"],
"permissions": ["read"]
}
)
List Profiles
result = client.exposure_profiles.list(user_id="user-123")
for profile in result['items']:
print(f"📋 {profile['name']}")
print(f" Types: {profile['scope'].get('node_types', 'all')}")
print(f" Permissions: {profile['scope'].get('permissions', [])}")
Update a Profile
updated = client.exposure_profiles.update(
user_id="user-123",
profile_id="profile_work123",
scope={
"node_types": ["note", "document", "task"],
"permissions": ["read", "write"]
}
)
Delete a Profile
client.exposure_profiles.delete(
user_id="user-123",
profile_id="profile_work123"
)
Common Profile Patterns
Read-Only Work Data
{
"name": "Work Read-Only",
"scope": {
"tag_ids": ["tag_work"],
"exclude_tag_ids": ["tag_confidential"],
"permissions": ["read"]
}
}
Notes Only (No Files)
{
"name": "Notes Only",
"scope": {
"node_types": ["note"],
"permissions": ["read"]
}
}
Full Access (Trusted App)
{
"name": "Full Access",
"scope": {
"permissions": ["read", "write", "delete"]
}
}
Journal App
{
"name": "Journal Data",
"scope": {
"node_types": ["memory", "journal"],
"tag_ids": ["tag_journal", "tag_personal"],
"permissions": ["read", "write"]
}
}
Using Profiles for Sharing
When a user authorizes your app, they select an exposure profile:
# Create a share using a profile
share = client.sharing.create(
user_id="user-123",
third_party_id="your-app-id",
exposure_profile_id="profile_work123"
)
Your app can only access data matching that profile's scope.
Default Profile
Users can set a default profile for quick authorization:
client.exposure_profiles.update(
user_id="user-123",
profile_id="profile_work123",
is_default=True
)
Best Practices
1. Request Minimum Permissions
Only ask for what you need:
# Good - specific and minimal
{
"node_types": ["note"],
"permissions": ["read"]
}
# Bad - overly broad
{
"permissions": ["read", "write", "delete"]
}
2. Explain What You Need
When users authorize your app, clearly explain why you need each permission.
3. Respect the Scope
Even if you have the API key, only access what the exposure profile allows. Attempting to access out-of-scope data will return 403 errors.
4. Support Multiple Profiles
Let users choose different profiles for different use cases:
# User might have:
# - "Work Notes" for a work productivity app
# - "Health Data" for a health tracking app
# - "Full Journal" for their journaling app
How Apps See Filtered Data
When your app calls the API with a user who has granted access via a profile:
# App calls list nodes
nodes = client.nodes.list(user_id="user-123")
# Only returns nodes matching the exposure profile:
# - Matching node_types
# - Having required tags
# - Not having excluded tags
The API automatically filters based on the active exposure profile.