@sprid/cli 0.1.2 → 0.1.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +11 -0
- package/package.json +1 -1
- package/src/commands/family.mjs +32 -2
- package/src/commands/init.mjs +1 -0
- package/src/commands/reviews.mjs +26 -17
- package/src/commands/studio.mjs +4 -2
- package/src/docs/commands.mjs +2 -1
- package/src/docs/guides.generated.mjs +243 -255
|
@@ -52,55 +52,55 @@ export const GUIDES = [
|
|
|
52
52
|
"id": "you-need",
|
|
53
53
|
"title": "You need",
|
|
54
54
|
"kind": "requirements",
|
|
55
|
-
"markdown": "- The email address that should own the accounts, access to its inbox, and your phone for verification.\n-
|
|
55
|
+
"markdown": "- The email address that should own the accounts, access to its inbox, and your phone for verification.\n- The display name, desired handle and purpose of each account. A handle is only a proposal until the platform accepts it.\n- Access to your Meta business portfolio, if it should own the Facebook Pages and Instagram accounts.\n\nPasswords, verification codes and identity documents stay in the platform’s own browser or app. An agent can prepare forms and continue after you sign in."
|
|
56
56
|
},
|
|
57
57
|
{
|
|
58
58
|
"id": "set-up-your-account-map",
|
|
59
59
|
"title": "Set up your account map",
|
|
60
60
|
"kind": "steps",
|
|
61
|
-
"markdown": "
|
|
61
|
+
"markdown": "Connect one main account, or several with different purposes. Choose only the accounts and platforms your audience needs.\n\n| Account purpose | Example display name | Example handle | Sprid publishing account |\n|---|---|---|---|\n| Main brand or product | Your Brand | yourbrand | yourbrand |\n| Founder or creator | Alex from Your Brand | alexfromyourbrand | brand-founder |\n| Character or persona | Everyday Alex | everydayalex | everyday-alex |\n| Topic or community | Small Space Ideas | smallspaceideas | small-space-ideas |\n| Campaign or project | The Weekend Project | theweekendproject | weekend-project |\n| Language or regional audience | Your Brand Español | yourbrand.espanol | brand-spanish |\n\nThe examples are naming ideas, not availability checks. The purpose is separate from platform settings such as Instagram’s Business or Creator type or Google’s Brand Account. A character account can represent a fictional persona; keep that clear in its profile.\n\nFor each identity, write down the owner, purpose, handle and platforms. Group the same identity’s profiles under one Sprid publishing account: your brand’s Instagram and YouTube share one, a founder’s account gets its own.\n\nAn Instagram login, a Facebook Page, a Meta business portfolio and a Sprid publishing account are separate objects. Connecting a channel to Sprid does not move its ownership into a portfolio, and a Sprid destination does not reserve a handle or create a social account.\n\nYour agent can list existing publishing accounts with `sprid apps` and create missing ones with `sprid account create --file account.json` (see the [CLI reference](https://sprid.studio/docs/cli))."
|
|
62
62
|
},
|
|
63
63
|
{
|
|
64
64
|
"id": "set-up-instagram",
|
|
65
65
|
"title": "Set up Instagram",
|
|
66
66
|
"kind": "steps",
|
|
67
|
-
"markdown": "1. Open [Instagram signup](https://www.instagram.com/accounts/emailsignup/)
|
|
67
|
+
"markdown": "1. Open [Instagram signup](https://www.instagram.com/accounts/emailsignup/), or reuse an existing account that already serves the purpose.\n2. Enter the owner email, display name and desired handle. Complete password, birthday and verification in Instagram.\n3. Check the profile’s actual handle and contact email.\n4. Switch to a professional account: **Business** for a brand, **Creator** for a creator-led account, with a matching category.\n5. If a Meta business portfolio should own it, its administrator adds the account there. This is separate from Sprid authorization.\n6. Follow the [Instagram connection guide](https://sprid.studio/docs/connect/instagram), one account at a time.\n\nThe Sprid connection may offer the professional switch itself: **Change → Business → Next → category → Done → Continue** (labels as of September 2026). If signing up an additional account sends you back to login, finish signup in a separate browser session or the Instagram app and keep the working account signed in."
|
|
68
68
|
},
|
|
69
69
|
{
|
|
70
70
|
"id": "set-up-facebook",
|
|
71
71
|
"title": "Set up Facebook",
|
|
72
72
|
"kind": "steps",
|
|
73
|
-
"markdown": "Reuse
|
|
73
|
+
"markdown": "Reuse an existing Page where you can. Otherwise open [Create a Page](https://www.facebook.com/pages/create/) under the profile that should manage it, using the public display name. If a business portfolio should own the Page, its administrator adds or claims it there. Then follow the [Facebook connection guide](https://sprid.studio/docs/connect/facebook)."
|
|
74
74
|
},
|
|
75
75
|
{
|
|
76
76
|
"id": "set-up-youtube",
|
|
77
77
|
"title": "Set up YouTube",
|
|
78
78
|
"kind": "steps",
|
|
79
|
-
"markdown": "Sign in to [YouTube’s channel list](https://www.youtube.com/channel_switcher) with the
|
|
79
|
+
"markdown": "Sign in to [YouTube’s channel list](https://www.youtube.com/channel_switcher) with the owner’s Google account. Review existing channels, then choose **Create a channel** for each additional identity. Check both the channel name and handle.\n\nIf YouTube asks for advanced-feature verification, the owner completes it in YouTube Studio (video, ID or channel history). Review can stay pending: continue other platforms and recheck eligibility before retrying. Approval on one channel does not unlock every new channel. See [YouTube eligibility and owner verification](https://support.google.com/youtube/answer/9891124?hl=en).\n\nThen follow the [YouTube connection guide](https://sprid.studio/docs/connect/youtube) and pick that exact channel in Google’s authorization screen."
|
|
80
80
|
},
|
|
81
81
|
{
|
|
82
82
|
"id": "set-up-tiktok",
|
|
83
83
|
"title": "Set up TikTok",
|
|
84
84
|
"kind": "steps",
|
|
85
|
-
"markdown": "Create or sign in to each
|
|
85
|
+
"markdown": "Create or sign in to each account in TikTok, confirm the handle and the owner’s recovery access, and complete any verification yourself. Then follow the [TikTok connection guide](https://sprid.studio/docs/connect/tiktok)."
|
|
86
86
|
},
|
|
87
87
|
{
|
|
88
88
|
"id": "then-run",
|
|
89
89
|
"title": "Then run",
|
|
90
90
|
"kind": "command",
|
|
91
|
-
"markdown": "```sh\nsprid connect instagram --account yourbrand\n```\n\
|
|
91
|
+
"markdown": "```sh\nsprid connect instagram --account yourbrand\n```\n\nUse your Sprid publishing-account slug and the platform: `instagram`, `facebook`, `youtube` or `tiktok`. Connect only accounts that already exist.\n\nIn an agent-controlled browser, add `--no-browser` and open the returned authorization link in the session signed in to the correct account. Keep that link private."
|
|
92
92
|
},
|
|
93
93
|
{
|
|
94
94
|
"id": "how-to-check-it-worked",
|
|
95
95
|
"title": "How to check it worked",
|
|
96
96
|
"kind": "verify",
|
|
97
|
-
"markdown": "Run `sprid status --json` and match
|
|
97
|
+
"markdown": "Run `sprid status --json` and match each platform identity to its Sprid publishing account. Track per platform:\n\n- Account created, with its confirmed handle or Page/channel ID.\n- Owner and business-portfolio access checked.\n- Provider verification or tester invitation still pending.\n- Sprid connection saved to the correct destination.\n- Publishing tested with approved content, or untested.\n\n“You allowed access” on the authorization screen does not prove Sprid saved the connection, and a connected channel does not prove a post was delivered. Check the platform itself after a publishing test."
|
|
98
98
|
},
|
|
99
99
|
{
|
|
100
100
|
"id": "if-it-fails",
|
|
101
101
|
"title": "If it fails",
|
|
102
102
|
"kind": "troubleshooting",
|
|
103
|
-
"markdown": "- **Another account appears in authorization:** cancel
|
|
103
|
+
"markdown": "- **Another account appears in authorization:** cancel, sign in to the intended account and restart. Do not move a working channel to clear the error.\n- **Several Facebook Pages are listed:** rerun with `--page <id>` using the intended Page’s returned ID.\n- **YouTube verification is pending:** leave that destination pending and continue with another platform.\n- **Instagram authorizes but Sprid reports a token-exchange error:** send the error to [Sprid support](mailto:hello@sprid.studio). Sprid checks its Meta permissions and tester restrictions; any tester invitation comes from Sprid and must be accepted by the intended Instagram account. You do not need your own developer app.\n- **The CLI points to an unavailable local server:** check `sprid whoami --json`, then retry with `SPRID_URL=https://api.sprid.studio` for that command. Do not change credentials or workspaces to fix a server-address mismatch."
|
|
104
104
|
},
|
|
105
105
|
{
|
|
106
106
|
"id": "sources",
|
|
@@ -109,8 +109,8 @@ export const GUIDES = [
|
|
|
109
109
|
"markdown": "- [Instagram signup](https://www.instagram.com/accounts/emailsignup/)\n- [Instagram Business Login](https://developers.facebook.com/docs/instagram-platform/instagram-api-with-instagram-login/business-login/)\n- [Meta app modes](https://developers.facebook.com/docs/development/build-and-test/app-modes)\n- [Meta Accounts Center](https://www.facebook.com/help/943858526073065)\n- [Create a Facebook Page](https://www.facebook.com/pages/create/)\n- [YouTube channel list](https://www.youtube.com/channel_switcher)\n- [YouTube feature eligibility](https://support.google.com/youtube/answer/9891124?hl=en)"
|
|
110
110
|
}
|
|
111
111
|
],
|
|
112
|
-
"markdown": "# Create your social accounts\n\n**What Sprid does with this:** Connect your brand, creator and other social accounts to their own publishing destinations, so approved content reaches the intended audience.\n\n## You need\n\n- The email address that should own the accounts, access to its inbox, and your phone for verification.\n-
|
|
113
|
-
"revision": "
|
|
112
|
+
"markdown": "# Create your social accounts\n\n**What Sprid does with this:** Connect your brand, creator and other social accounts to their own publishing destinations, so approved content reaches the intended audience.\n\n## You need\n\n- The email address that should own the accounts, access to its inbox, and your phone for verification.\n- The display name, desired handle and purpose of each account. A handle is only a proposal until the platform accepts it.\n- Access to your Meta business portfolio, if it should own the Facebook Pages and Instagram accounts.\n\nPasswords, verification codes and identity documents stay in the platform’s own browser or app. An agent can prepare forms and continue after you sign in.\n\n## Set up your account map\n\nConnect one main account, or several with different purposes. Choose only the accounts and platforms your audience needs.\n\n| Account purpose | Example display name | Example handle | Sprid publishing account |\n|---|---|---|---|\n| Main brand or product | Your Brand | yourbrand | yourbrand |\n| Founder or creator | Alex from Your Brand | alexfromyourbrand | brand-founder |\n| Character or persona | Everyday Alex | everydayalex | everyday-alex |\n| Topic or community | Small Space Ideas | smallspaceideas | small-space-ideas |\n| Campaign or project | The Weekend Project | theweekendproject | weekend-project |\n| Language or regional audience | Your Brand Español | yourbrand.espanol | brand-spanish |\n\nThe examples are naming ideas, not availability checks. The purpose is separate from platform settings such as Instagram’s Business or Creator type or Google’s Brand Account. A character account can represent a fictional persona; keep that clear in its profile.\n\nFor each identity, write down the owner, purpose, handle and platforms. Group the same identity’s profiles under one Sprid publishing account: your brand’s Instagram and YouTube share one, a founder’s account gets its own.\n\nAn Instagram login, a Facebook Page, a Meta business portfolio and a Sprid publishing account are separate objects. Connecting a channel to Sprid does not move its ownership into a portfolio, and a Sprid destination does not reserve a handle or create a social account.\n\nYour agent can list existing publishing accounts with `sprid apps` and create missing ones with `sprid account create --file account.json` (see the [CLI reference](https://sprid.studio/docs/cli)).\n\n## Set up Instagram\n\n1. Open [Instagram signup](https://www.instagram.com/accounts/emailsignup/), or reuse an existing account that already serves the purpose.\n2. Enter the owner email, display name and desired handle. Complete password, birthday and verification in Instagram.\n3. Check the profile’s actual handle and contact email.\n4. Switch to a professional account: **Business** for a brand, **Creator** for a creator-led account, with a matching category.\n5. If a Meta business portfolio should own it, its administrator adds the account there. This is separate from Sprid authorization.\n6. Follow the [Instagram connection guide](https://sprid.studio/docs/connect/instagram), one account at a time.\n\nThe Sprid connection may offer the professional switch itself: **Change → Business → Next → category → Done → Continue** (labels as of September 2026). If signing up an additional account sends you back to login, finish signup in a separate browser session or the Instagram app and keep the working account signed in.\n\n## Set up Facebook\n\nReuse an existing Page where you can. Otherwise open [Create a Page](https://www.facebook.com/pages/create/) under the profile that should manage it, using the public display name. If a business portfolio should own the Page, its administrator adds or claims it there. Then follow the [Facebook connection guide](https://sprid.studio/docs/connect/facebook).\n\n## Set up YouTube\n\nSign in to [YouTube’s channel list](https://www.youtube.com/channel_switcher) with the owner’s Google account. Review existing channels, then choose **Create a channel** for each additional identity. Check both the channel name and handle.\n\nIf YouTube asks for advanced-feature verification, the owner completes it in YouTube Studio (video, ID or channel history). Review can stay pending: continue other platforms and recheck eligibility before retrying. Approval on one channel does not unlock every new channel. See [YouTube eligibility and owner verification](https://support.google.com/youtube/answer/9891124?hl=en).\n\nThen follow the [YouTube connection guide](https://sprid.studio/docs/connect/youtube) and pick that exact channel in Google’s authorization screen.\n\n## Set up TikTok\n\nCreate or sign in to each account in TikTok, confirm the handle and the owner’s recovery access, and complete any verification yourself. Then follow the [TikTok connection guide](https://sprid.studio/docs/connect/tiktok).\n\n## Then run\n\n```sh\nsprid connect instagram --account yourbrand\n```\n\nUse your Sprid publishing-account slug and the platform: `instagram`, `facebook`, `youtube` or `tiktok`. Connect only accounts that already exist.\n\nIn an agent-controlled browser, add `--no-browser` and open the returned authorization link in the session signed in to the correct account. Keep that link private.\n\n## How to check it worked\n\nRun `sprid status --json` and match each platform identity to its Sprid publishing account. Track per platform:\n\n- Account created, with its confirmed handle or Page/channel ID.\n- Owner and business-portfolio access checked.\n- Provider verification or tester invitation still pending.\n- Sprid connection saved to the correct destination.\n- Publishing tested with approved content, or untested.\n\n“You allowed access” on the authorization screen does not prove Sprid saved the connection, and a connected channel does not prove a post was delivered. Check the platform itself after a publishing test.\n\n## If it fails\n\n- **Another account appears in authorization:** cancel, sign in to the intended account and restart. Do not move a working channel to clear the error.\n- **Several Facebook Pages are listed:** rerun with `--page <id>` using the intended Page’s returned ID.\n- **YouTube verification is pending:** leave that destination pending and continue with another platform.\n- **Instagram authorizes but Sprid reports a token-exchange error:** send the error to [Sprid support](mailto:hello@sprid.studio). Sprid checks its Meta permissions and tester restrictions; any tester invitation comes from Sprid and must be accepted by the intended Instagram account. You do not need your own developer app.\n- **The CLI points to an unavailable local server:** check `sprid whoami --json`, then retry with `SPRID_URL=https://api.sprid.studio` for that command. Do not change credentials or workspaces to fix a server-address mismatch.\n\n## Sources\n\n- [Instagram signup](https://www.instagram.com/accounts/emailsignup/)\n- [Instagram Business Login](https://developers.facebook.com/docs/instagram-platform/instagram-api-with-instagram-login/business-login/)\n- [Meta app modes](https://developers.facebook.com/docs/development/build-and-test/app-modes)\n- [Meta Accounts Center](https://www.facebook.com/help/943858526073065)\n- [Create a Facebook Page](https://www.facebook.com/pages/create/)\n- [YouTube channel list](https://www.youtube.com/channel_switcher)\n- [YouTube feature eligibility](https://support.google.com/youtube/answer/9891124?hl=en)\n",
|
|
113
|
+
"revision": "fc2505d0782288a4"
|
|
114
114
|
},
|
|
115
115
|
{
|
|
116
116
|
"id": "app-store-connect",
|
|
@@ -123,53 +123,53 @@ export const GUIDES = [
|
|
|
123
123
|
"id": "you-need",
|
|
124
124
|
"title": "You need",
|
|
125
125
|
"kind": "requirements",
|
|
126
|
-
"markdown": "**Account Holder** or **Admin** access to your Apple Developer team
|
|
126
|
+
"markdown": "**Account Holder** or **Admin** access to your Apple Developer team, to create a **Team API key** with **Admin** access. One key covers every app on the account.\n\n**App Manager** is enough to read reviews and edit metadata. Review replies and analytics reports need Admin."
|
|
127
127
|
},
|
|
128
128
|
{
|
|
129
129
|
"id": "click-path-appstoreconnectapplecom-checked-2026-09-08",
|
|
130
130
|
"title": "Click path (appstoreconnect.apple.com, checked 2026-09-08)",
|
|
131
131
|
"kind": "steps",
|
|
132
|
-
"markdown": "1. Open [App Store Connect](https://appstoreconnect.apple.com) → **Users and Access → Integrations → App Store Connect API → Team Keys**.\n2. Click **Generate API Key**, or **+** beside **Active**.\n3. Name
|
|
132
|
+
"markdown": "1. Open [App Store Connect](https://appstoreconnect.apple.com) → **Users and Access → Integrations → App Store Connect API → Team Keys**.\n2. Click **Generate API Key**, or **+** beside **Active**.\n3. Name it `Sprid`, choose **Admin**, then **Generate**.\n4. Click **Download API Key** and keep the `.p8` file. Apple offers the download once; if you lose it, revoke the key and make another.\n5. Copy the **Key ID** from its row and the **Issuer ID** above the table."
|
|
133
133
|
},
|
|
134
134
|
{
|
|
135
135
|
"id": "find-the-apps-numeric-id",
|
|
136
136
|
"title": "Find the app's numeric id",
|
|
137
137
|
"kind": "identifiers",
|
|
138
|
-
"markdown": "
|
|
138
|
+
"markdown": "**Apps → your app → General → App Information → General Information → Apple ID**. If your Sprid app profile lacks it, run `sprid init`."
|
|
139
139
|
},
|
|
140
140
|
{
|
|
141
141
|
"id": "then-run",
|
|
142
142
|
"title": "Then run",
|
|
143
143
|
"kind": "command",
|
|
144
|
-
"markdown": "```\nsprid connect asc --key ~/Downloads/AuthKey_XXXXXXXXXX.p8 --key-id XXXXXXXXXX --issuer YYYYYYYY-YYYY-YYYY-YYYY-YYYYYYYYYYYY\n```\n\
|
|
144
|
+
"markdown": "```\nsprid connect asc --key ~/Downloads/AuthKey_XXXXXXXXXX.p8 --key-id XXXXXXXXXX --issuer YYYYYYYY-YYYY-YYYY-YYYY-YYYYYYYYYYYY\n```\n\nUse your own file path and ids. Keep the key file out of chat."
|
|
145
145
|
},
|
|
146
146
|
{
|
|
147
147
|
"id": "how-to-check-it-worked",
|
|
148
148
|
"title": "How to check it worked",
|
|
149
149
|
"kind": "verify",
|
|
150
|
-
"markdown": "Run `sprid status
|
|
150
|
+
"markdown": "Run `sprid status`, then ask your agent: “Check that Sprid can read this app’s App Store reviews and analytics. Tell me if any reports are still missing.” A saved key alone does not confirm access. The daily review email only arrives when there are new reviews."
|
|
151
151
|
},
|
|
152
152
|
{
|
|
153
153
|
"id": "if-it-fails",
|
|
154
154
|
"title": "If it fails",
|
|
155
155
|
"kind": "troubleshooting",
|
|
156
|
-
"markdown": "- **Key not accepted:** check the Key ID matches the downloaded file and the Issuer ID came from above the keys table. A Team ID will not work
|
|
156
|
+
"markdown": "- **Key not accepted:** check the Key ID matches the downloaded file and the Issuer ID came from above the keys table. A Team ID will not work.\n- **Permission denied:** create a replacement key with **Admin** access. A key’s role cannot be changed.\n- **Older analytics are missing:** Apple starts preparing reports after setup. Missing history does not mean downloads fell to zero."
|
|
157
|
+
},
|
|
158
|
+
{
|
|
159
|
+
"id": "investigate-with-this-connection",
|
|
160
|
+
"title": "Investigate with this connection",
|
|
161
|
+
"kind": "detail",
|
|
162
|
+
"markdown": "Reads `reviews`, `versions`, `reports` and `report_rows` for the pinned app. Read-only: no report request is created.\n\n```sh\nsprid marketing-review capabilities --app <slug> --source asc --json\n```\n\nSee [connected queries](https://sprid.studio/docs/queries)."
|
|
157
163
|
},
|
|
158
164
|
{
|
|
159
165
|
"id": "sources",
|
|
160
166
|
"title": "Sources",
|
|
161
167
|
"kind": "sources",
|
|
162
168
|
"markdown": "- [Generate keys](https://developer.apple.com/help/app-store-connect/get-started/app-store-connect-api)\n- [Role permissions](https://developer.apple.com/help/app-store-connect/reference/account-management/role-permissions)\n- [Respond to reviews](https://developer.apple.com/help/app-store-connect/monitor-ratings-and-reviews/respond-to-reviews)\n- [API key access levels compared](https://aso.dev/app-store-connect/api-key-access-levels/)\n- [App Manager 403 on review replies](https://developer.apple.com/forums/thread/800545)"
|
|
163
|
-
},
|
|
164
|
-
{
|
|
165
|
-
"id": "investigate-with-this-connection",
|
|
166
|
-
"title": "Investigate with this connection",
|
|
167
|
-
"kind": "detail",
|
|
168
|
-
"markdown": "Your agent can use `list_marketing_queries` and `query_marketing_source` for `reviews`, `versions`, `reports`, `report_rows`. Discover the exact parameters and required setup with:\n\n```sh\nsprid marketing-review capabilities --app <slug> --source asc --json\n```\n\nPinned app. Reviews and existing analytics report definitions are read-only. No report request is created. See [connected queries](https://sprid.studio/docs/queries) for the shared workflow. Extra operations may need additional read permissions; a stored key alone is not live verification."
|
|
169
169
|
}
|
|
170
170
|
],
|
|
171
|
-
"markdown": "# App Store Connect\n\n**What Sprid does with this:** Read App Store reviews and download reports, and update listing copy when you approve it.\n\n## You need\n\n**Account Holder** or **Admin** access to your Apple Developer team
|
|
172
|
-
"revision": "
|
|
171
|
+
"markdown": "# App Store Connect\n\n**What Sprid does with this:** Read App Store reviews and download reports, and update listing copy when you approve it.\n\n## You need\n\n**Account Holder** or **Admin** access to your Apple Developer team, to create a **Team API key** with **Admin** access. One key covers every app on the account.\n\n**App Manager** is enough to read reviews and edit metadata. Review replies and analytics reports need Admin.\n\n## Click path (appstoreconnect.apple.com, checked 2026-09-08)\n\n1. Open [App Store Connect](https://appstoreconnect.apple.com) → **Users and Access → Integrations → App Store Connect API → Team Keys**.\n2. Click **Generate API Key**, or **+** beside **Active**.\n3. Name it `Sprid`, choose **Admin**, then **Generate**.\n4. Click **Download API Key** and keep the `.p8` file. Apple offers the download once; if you lose it, revoke the key and make another.\n5. Copy the **Key ID** from its row and the **Issuer ID** above the table.\n\n## Find the app's numeric id\n\n**Apps → your app → General → App Information → General Information → Apple ID**. If your Sprid app profile lacks it, run `sprid init`.\n\n## Then run\n\n```\nsprid connect asc --key ~/Downloads/AuthKey_XXXXXXXXXX.p8 --key-id XXXXXXXXXX --issuer YYYYYYYY-YYYY-YYYY-YYYY-YYYYYYYYYYYY\n```\n\nUse your own file path and ids. Keep the key file out of chat.\n\n## How to check it worked\n\nRun `sprid status`, then ask your agent: “Check that Sprid can read this app’s App Store reviews and analytics. Tell me if any reports are still missing.” A saved key alone does not confirm access. The daily review email only arrives when there are new reviews.\n\n## If it fails\n\n- **Key not accepted:** check the Key ID matches the downloaded file and the Issuer ID came from above the keys table. A Team ID will not work.\n- **Permission denied:** create a replacement key with **Admin** access. A key’s role cannot be changed.\n- **Older analytics are missing:** Apple starts preparing reports after setup. Missing history does not mean downloads fell to zero.\n\n## Investigate with this connection\n\nReads `reviews`, `versions`, `reports` and `report_rows` for the pinned app. Read-only: no report request is created.\n\n```sh\nsprid marketing-review capabilities --app <slug> --source asc --json\n```\n\nSee [connected queries](https://sprid.studio/docs/queries).\n\n## Sources\n\n- [Generate keys](https://developer.apple.com/help/app-store-connect/get-started/app-store-connect-api)\n- [Role permissions](https://developer.apple.com/help/app-store-connect/reference/account-management/role-permissions)\n- [Respond to reviews](https://developer.apple.com/help/app-store-connect/monitor-ratings-and-reviews/respond-to-reviews)\n- [API key access levels compared](https://aso.dev/app-store-connect/api-key-access-levels/)\n- [App Manager 403 on review replies](https://developer.apple.com/forums/thread/800545)\n",
|
|
172
|
+
"revision": "b20748bb9f9756c8"
|
|
173
173
|
},
|
|
174
174
|
{
|
|
175
175
|
"id": "google-play",
|
|
@@ -182,53 +182,53 @@ export const GUIDES = [
|
|
|
182
182
|
"id": "you-need",
|
|
183
183
|
"title": "You need",
|
|
184
184
|
"kind": "requirements",
|
|
185
|
-
"markdown": "**Owner** or **Admin** access in Play Console,
|
|
185
|
+
"markdown": "**Owner** or **Admin** access in Play Console, and a Google Cloud project where you can create a service account. The project does not need to be linked to Play Console."
|
|
186
186
|
},
|
|
187
187
|
{
|
|
188
188
|
"id": "click-path",
|
|
189
189
|
"title": "Click path",
|
|
190
190
|
"kind": "steps",
|
|
191
|
-
"markdown": "### A. Google Cloud\n\n1. Open [Google Cloud](https://console.cloud.google.com) and select or create a project.\n2.
|
|
191
|
+
"markdown": "### A. Google Cloud\n\n1. Open [Google Cloud](https://console.cloud.google.com) and select or create a project.\n2. **APIs & Services → Library**: enable **Google Play Android Developer API**. For statistics reports, also enable **Google Play Developer Reporting API**.\n3. **IAM & Admin → Service Accounts → Create service account**. Name it `sprid-play`, click **Create and continue**, then **Done**. Leave Cloud roles empty.\n4. Open the account → **Keys → Add key → Create new key → JSON → Create**. Save it as `play-sa.json` and keep it private.\n5. Copy the service account’s email.\n\n### B. Play Console\n\n6. Open [Play Console](https://play.google.com/console) → **Users and permissions → Invite new users**. Enter the service account’s email; leave access expiry unset.\n7. **App permissions → Add app**: select your app, then **Apply**.\n8. Enable **View app information (read-only)** and **Reply to reviews**. Add **Manage store presence** to update listing copy. Leave financial access off.\n9. Click **Invite user → Send invite**."
|
|
192
192
|
},
|
|
193
193
|
{
|
|
194
194
|
"id": "find-the-package-name",
|
|
195
195
|
"title": "Find the package name",
|
|
196
196
|
"kind": "identifiers",
|
|
197
|
-
"markdown": "Copy
|
|
197
|
+
"markdown": "Copy it from beneath your app’s name on its Play Console **Dashboard**, such as `com.example.app`. Run `sprid init` if your Sprid app profile lacks it.\n\nFor download reports, copy the **Cloud Storage URI** from **Download reports → Statistics** into `playExportBucket` in `.sprid/app.json`. These also need the account-level **View app information and download bulk reports (read-only)** permission."
|
|
198
198
|
},
|
|
199
199
|
{
|
|
200
200
|
"id": "then-run",
|
|
201
201
|
"title": "Then run",
|
|
202
202
|
"kind": "command",
|
|
203
|
-
"markdown": "```\nsprid connect play --key ~/Downloads/play-sa.json\n```\n\nUse
|
|
203
|
+
"markdown": "```\nsprid connect play --key ~/Downloads/play-sa.json\n```\n\nUse your own file path. Keep its contents out of chat."
|
|
204
204
|
},
|
|
205
205
|
{
|
|
206
206
|
"id": "how-to-check-it-worked",
|
|
207
207
|
"title": "How to check it worked",
|
|
208
208
|
"kind": "verify",
|
|
209
|
-
"markdown": "Run `sprid status`, then ask your agent: “Check that Sprid can read this app’s Play reviews and download reports. Tell me what is missing
|
|
209
|
+
"markdown": "Run `sprid status`, then ask your agent: “Check that Sprid can read this app’s Play reviews and download reports. Tell me what is missing.” The review email only arrives when there are new reviews."
|
|
210
210
|
},
|
|
211
211
|
{
|
|
212
212
|
"id": "if-it-fails",
|
|
213
213
|
"title": "If it fails",
|
|
214
214
|
"kind": "troubleshooting",
|
|
215
|
-
"markdown": "- **Permission denied:** check the service account appears under **Users and permissions** with your app selected. New permissions
|
|
215
|
+
"markdown": "- **Permission denied:** check the service account appears under **Users and permissions** with your app selected. New permissions can take time; integrators report up to 24 hours, which Google’s docs do not confirm.\n- **Google Play’s API is switched off:** enable **Google Play Android Developer API** in the service account’s Cloud project. Sprid’s error message links to it.\n- **Reviews are empty:** Google’s API only returns recent reviews with written text. Older reviews and star-only ratings stay visible in the store but not to Sprid."
|
|
216
|
+
},
|
|
217
|
+
{
|
|
218
|
+
"id": "investigate-with-this-connection",
|
|
219
|
+
"title": "Investigate with this connection",
|
|
220
|
+
"kind": "detail",
|
|
221
|
+
"markdown": "Reads `reviews` and `report_rows` for the pinned package. Reviews are limited by Google’s history window; report rows need the saved export bucket.\n\n```sh\nsprid marketing-review capabilities --app <slug> --source play --json\n```\n\nSee [connected queries](https://sprid.studio/docs/queries)."
|
|
216
222
|
},
|
|
217
223
|
{
|
|
218
224
|
"id": "sources",
|
|
219
225
|
"title": "Sources",
|
|
220
226
|
"kind": "sources",
|
|
221
227
|
"markdown": "- [Getting started](https://developers.google.com/android-publisher/getting_started)\n- [Permission names in Users and permissions](https://support.google.com/googleplay/android-developer/answer/9844686)\n- [Reviews API only returns recent reviews](https://developers.google.com/android-publisher/reply-to-reviews)\n- [24-hour propagation](https://docs.apphud.com/docs/google-play-service-credentials)\n- [24-hour propagation](https://documentation.qonversion.io/docs/service-account-key-android)"
|
|
222
|
-
},
|
|
223
|
-
{
|
|
224
|
-
"id": "investigate-with-this-connection",
|
|
225
|
-
"title": "Investigate with this connection",
|
|
226
|
-
"kind": "detail",
|
|
227
|
-
"markdown": "Your agent can use `list_marketing_queries` and `query_marketing_source` for `reviews`, `report_rows`. Discover the exact parameters and required setup with:\n\n```sh\nsprid marketing-review capabilities --app <slug> --source play --json\n```\n\nPinned package. Live reviews have provider history limits; exported acquisition rows require the saved Play export bucket. See [connected queries](https://sprid.studio/docs/queries) for the shared workflow. Extra operations may need additional read permissions; a stored key alone is not live verification."
|
|
228
228
|
}
|
|
229
229
|
],
|
|
230
|
-
"markdown": "# Google Play\n\n**What Sprid does with this:** Read Google Play reviews and download reports, and update listing copy when you approve it.\n\n## You need\n\n**Owner** or **Admin** access in Play Console,
|
|
231
|
-
"revision": "
|
|
230
|
+
"markdown": "# Google Play\n\n**What Sprid does with this:** Read Google Play reviews and download reports, and update listing copy when you approve it.\n\n## You need\n\n**Owner** or **Admin** access in Play Console, and a Google Cloud project where you can create a service account. The project does not need to be linked to Play Console.\n\n## Click path\n\n### A. Google Cloud\n\n1. Open [Google Cloud](https://console.cloud.google.com) and select or create a project.\n2. **APIs & Services → Library**: enable **Google Play Android Developer API**. For statistics reports, also enable **Google Play Developer Reporting API**.\n3. **IAM & Admin → Service Accounts → Create service account**. Name it `sprid-play`, click **Create and continue**, then **Done**. Leave Cloud roles empty.\n4. Open the account → **Keys → Add key → Create new key → JSON → Create**. Save it as `play-sa.json` and keep it private.\n5. Copy the service account’s email.\n\n### B. Play Console\n\n6. Open [Play Console](https://play.google.com/console) → **Users and permissions → Invite new users**. Enter the service account’s email; leave access expiry unset.\n7. **App permissions → Add app**: select your app, then **Apply**.\n8. Enable **View app information (read-only)** and **Reply to reviews**. Add **Manage store presence** to update listing copy. Leave financial access off.\n9. Click **Invite user → Send invite**.\n\n## Find the package name\n\nCopy it from beneath your app’s name on its Play Console **Dashboard**, such as `com.example.app`. Run `sprid init` if your Sprid app profile lacks it.\n\nFor download reports, copy the **Cloud Storage URI** from **Download reports → Statistics** into `playExportBucket` in `.sprid/app.json`. These also need the account-level **View app information and download bulk reports (read-only)** permission.\n\n## Then run\n\n```\nsprid connect play --key ~/Downloads/play-sa.json\n```\n\nUse your own file path. Keep its contents out of chat.\n\n## How to check it worked\n\nRun `sprid status`, then ask your agent: “Check that Sprid can read this app’s Play reviews and download reports. Tell me what is missing.” The review email only arrives when there are new reviews.\n\n## If it fails\n\n- **Permission denied:** check the service account appears under **Users and permissions** with your app selected. New permissions can take time; integrators report up to 24 hours, which Google’s docs do not confirm.\n- **Google Play’s API is switched off:** enable **Google Play Android Developer API** in the service account’s Cloud project. Sprid’s error message links to it.\n- **Reviews are empty:** Google’s API only returns recent reviews with written text. Older reviews and star-only ratings stay visible in the store but not to Sprid.\n\n## Investigate with this connection\n\nReads `reviews` and `report_rows` for the pinned package. Reviews are limited by Google’s history window; report rows need the saved export bucket.\n\n```sh\nsprid marketing-review capabilities --app <slug> --source play --json\n```\n\nSee [connected queries](https://sprid.studio/docs/queries).\n\n## Sources\n\n- [Getting started](https://developers.google.com/android-publisher/getting_started)\n- [Permission names in Users and permissions](https://support.google.com/googleplay/android-developer/answer/9844686)\n- [Reviews API only returns recent reviews](https://developers.google.com/android-publisher/reply-to-reviews)\n- [24-hour propagation](https://docs.apphud.com/docs/google-play-service-credentials)\n- [24-hour propagation](https://documentation.qonversion.io/docs/service-account-key-android)\n",
|
|
231
|
+
"revision": "af1abe2a96ae39ec"
|
|
232
232
|
},
|
|
233
233
|
{
|
|
234
234
|
"id": "search-console",
|
|
@@ -241,53 +241,53 @@ export const GUIDES = [
|
|
|
241
241
|
"id": "you-need",
|
|
242
242
|
"title": "You need",
|
|
243
243
|
"kind": "requirements",
|
|
244
|
-
"markdown": "**Owner** access to your website’s Search Console property. You can reuse the
|
|
244
|
+
"markdown": "**Owner** access to your website’s Search Console property. You can reuse the service account from Sprid’s Play connection."
|
|
245
245
|
},
|
|
246
246
|
{
|
|
247
247
|
"id": "click-path",
|
|
248
248
|
"title": "Click path",
|
|
249
249
|
"kind": "steps",
|
|
250
|
-
"markdown": "### A. Google Cloud\n\n1. Open [Google Cloud](https://console.cloud.google.com) and select
|
|
250
|
+
"markdown": "### A. Google Cloud\n\n1. Open [Google Cloud](https://console.cloud.google.com) and select your service account’s project.\n2. **APIs & Services → Library**: enable **Google Search Console API**.\n3. No service account yet? **IAM & Admin → Service Accounts → Create service account**, name it `sprid-gsc`, then **Done**.\n4. Open the account → **Keys → Add key → Create new key → JSON**. Save it as `gsc-sa.json` and copy the account’s email. Reusing an account? Use its existing key file and email.\n\n### B. Search Console\n\n5. Open [Search Console](https://search.google.com/search-console) and select your website in the top-left dropdown.\n6. **Settings → Users and permissions → Add user**.\n7. Enter the service account’s email, choose **Restricted**, then **Add**."
|
|
251
251
|
},
|
|
252
252
|
{
|
|
253
253
|
"id": "domain-property-vs-url-prefix-and-the-property-string",
|
|
254
254
|
"title": "Domain property vs URL prefix, and the property string",
|
|
255
255
|
"kind": "identifiers",
|
|
256
|
-
"markdown": "
|
|
256
|
+
"markdown": "| Property shown in Search Console | Value to use |\n|---|---|\n| Domain, such as `example.com` | `sc-domain:example.com` |\n| URL prefix, such as `https://www.example.com/` | The exact URL, including its final slash |\n\nA domain property covers every version of your domain. **Settings → Property settings** shows which kind you have."
|
|
257
257
|
},
|
|
258
258
|
{
|
|
259
259
|
"id": "then-run",
|
|
260
260
|
"title": "Then run",
|
|
261
261
|
"kind": "command",
|
|
262
|
-
"markdown": "```\nsprid connect gsc --key ~/Downloads/gsc-sa.json --property sc-domain:example.com\n```\n\
|
|
262
|
+
"markdown": "```\nsprid connect gsc --key ~/Downloads/gsc-sa.json --property sc-domain:example.com\n```\n\nUse your own file path and property. Keep the file private."
|
|
263
263
|
},
|
|
264
264
|
{
|
|
265
265
|
"id": "how-to-check-it-worked",
|
|
266
266
|
"title": "How to check it worked",
|
|
267
267
|
"kind": "verify",
|
|
268
|
-
"markdown": "Run `sprid status`, then ask your agent: “Read recent Google search results for this website through Sprid and check that the property is correct
|
|
268
|
+
"markdown": "Run `sprid status`, then ask your agent: “Read recent Google search results for this website through Sprid and check that the property is correct.” A saved key confirms setup; only the live read confirms access. The newest few days may be missing because Google reports late."
|
|
269
269
|
},
|
|
270
270
|
{
|
|
271
271
|
"id": "if-it-fails",
|
|
272
272
|
"title": "If it fails",
|
|
273
273
|
"kind": "troubleshooting",
|
|
274
|
-
"markdown": "- **Access denied:** check the service account’s email was added to the exact property in your command. If both match, try **Full** permission. Do not grant Owner.\n- **Property not found:** check the domain or URL, including `www`, `https` and the final slash.\n- **Recent dates are empty:** try an earlier period; the latest
|
|
274
|
+
"markdown": "- **Access denied:** check the service account’s email was added to the exact property in your command. If both match, try **Full** permission. Do not grant Owner.\n- **Property not found:** check the domain or URL, including `www`, `https` and the final slash.\n- **Recent dates are empty:** try an earlier period; the latest days may still be processing."
|
|
275
|
+
},
|
|
276
|
+
{
|
|
277
|
+
"id": "investigate-with-this-connection",
|
|
278
|
+
"title": "Investigate with this connection",
|
|
279
|
+
"kind": "detail",
|
|
280
|
+
"markdown": "Reads `search` for the pinned property. Dates are Pacific time; anonymized queries and top-row limits reduce coverage.\n\n```sh\nsprid marketing-review capabilities --app <slug> --source gsc --json\n```\n\nSee [connected queries](https://sprid.studio/docs/queries)."
|
|
275
281
|
},
|
|
276
282
|
{
|
|
277
283
|
"id": "sources",
|
|
278
284
|
"title": "Sources",
|
|
279
285
|
"kind": "sources",
|
|
280
286
|
"markdown": "- [Permission levels and Add user path](https://support.google.com/webmasters/answer/7687615)\n- [`siteUrl` formats](https://developers.google.com/webmaster-tools/v1/searchanalytics/query)\n- [Service account rights vs Owner](https://www.indexernow.com/fix/service-account-owner-gsc)"
|
|
281
|
-
},
|
|
282
|
-
{
|
|
283
|
-
"id": "investigate-with-this-connection",
|
|
284
|
-
"title": "Investigate with this connection",
|
|
285
|
-
"kind": "detail",
|
|
286
|
-
"markdown": "Your agent can use `list_marketing_queries` and `query_marketing_source` for `search`. Discover the exact parameters and required setup with:\n\n```sh\nsprid marketing-review capabilities --app <slug> --source gsc --json\n```\n\nPinned Search Console property. Dates use Pacific time; anonymized queries and top-row limits affect coverage. See [connected queries](https://sprid.studio/docs/queries) for the shared workflow. Extra operations may need additional read permissions; a stored key alone is not live verification."
|
|
287
287
|
}
|
|
288
288
|
],
|
|
289
|
-
"markdown": "# Google Search Console\n\n**What Sprid does with this:** See which Google searches bring people to your website.\n\n## You need\n\n**Owner** access to your website’s Search Console property. You can reuse the
|
|
290
|
-
"revision": "
|
|
289
|
+
"markdown": "# Google Search Console\n\n**What Sprid does with this:** See which Google searches bring people to your website.\n\n## You need\n\n**Owner** access to your website’s Search Console property. You can reuse the service account from Sprid’s Play connection.\n\n## Click path\n\n### A. Google Cloud\n\n1. Open [Google Cloud](https://console.cloud.google.com) and select your service account’s project.\n2. **APIs & Services → Library**: enable **Google Search Console API**.\n3. No service account yet? **IAM & Admin → Service Accounts → Create service account**, name it `sprid-gsc`, then **Done**.\n4. Open the account → **Keys → Add key → Create new key → JSON**. Save it as `gsc-sa.json` and copy the account’s email. Reusing an account? Use its existing key file and email.\n\n### B. Search Console\n\n5. Open [Search Console](https://search.google.com/search-console) and select your website in the top-left dropdown.\n6. **Settings → Users and permissions → Add user**.\n7. Enter the service account’s email, choose **Restricted**, then **Add**.\n\n## Domain property vs URL prefix, and the property string\n\n| Property shown in Search Console | Value to use |\n|---|---|\n| Domain, such as `example.com` | `sc-domain:example.com` |\n| URL prefix, such as `https://www.example.com/` | The exact URL, including its final slash |\n\nA domain property covers every version of your domain. **Settings → Property settings** shows which kind you have.\n\n## Then run\n\n```\nsprid connect gsc --key ~/Downloads/gsc-sa.json --property sc-domain:example.com\n```\n\nUse your own file path and property. Keep the file private.\n\n## How to check it worked\n\nRun `sprid status`, then ask your agent: “Read recent Google search results for this website through Sprid and check that the property is correct.” A saved key confirms setup; only the live read confirms access. The newest few days may be missing because Google reports late.\n\n## If it fails\n\n- **Access denied:** check the service account’s email was added to the exact property in your command. If both match, try **Full** permission. Do not grant Owner.\n- **Property not found:** check the domain or URL, including `www`, `https` and the final slash.\n- **Recent dates are empty:** try an earlier period; the latest days may still be processing.\n\n## Investigate with this connection\n\nReads `search` for the pinned property. Dates are Pacific time; anonymized queries and top-row limits reduce coverage.\n\n```sh\nsprid marketing-review capabilities --app <slug> --source gsc --json\n```\n\nSee [connected queries](https://sprid.studio/docs/queries).\n\n## Sources\n\n- [Permission levels and Add user path](https://support.google.com/webmasters/answer/7687615)\n- [`siteUrl` formats](https://developers.google.com/webmaster-tools/v1/searchanalytics/query)\n- [Service account rights vs Owner](https://www.indexernow.com/fix/service-account-owner-gsc)\n",
|
|
290
|
+
"revision": "517fc192cac5962e"
|
|
291
291
|
},
|
|
292
292
|
{
|
|
293
293
|
"id": "posthog",
|
|
@@ -300,71 +300,71 @@ export const GUIDES = [
|
|
|
300
300
|
"id": "you-need",
|
|
301
301
|
"title": "You need",
|
|
302
302
|
"kind": "requirements",
|
|
303
|
-
"markdown": "Access to your app’s PostHog project and permission to create a **personal API key**. Your app must already send events to PostHog; connecting Sprid does not
|
|
303
|
+
"markdown": "Access to your app’s PostHog project and permission to create a **personal API key**. Your app must already send events to PostHog; connecting Sprid adds no tracking. The public key inside your app does not work here."
|
|
304
304
|
},
|
|
305
305
|
{
|
|
306
306
|
"id": "click-path-usposthogcom-or-euposthogcom",
|
|
307
307
|
"title": "Click path (us.posthog.com or eu.posthog.com)",
|
|
308
308
|
"kind": "steps",
|
|
309
|
-
"markdown": "1.
|
|
309
|
+
"markdown": "1. **Settings → Account → Personal API keys → Create personal API key**, named `Sprid <app name>`.\n2. Under access, select **Projects** and choose your app’s project. Leave **All access** off.\n3. Select **Query → Read** and **Project → Read**. Leave write access off.\n4. Copy the key before closing the dialog and save it to a private file such as `~/keys/posthog-myapp.txt`. Use a separate key per app."
|
|
310
310
|
},
|
|
311
311
|
{
|
|
312
312
|
"id": "project-id-and-host",
|
|
313
313
|
"title": "Project id and host",
|
|
314
314
|
"kind": "identifiers",
|
|
315
|
-
"markdown": "- **Project id:** the number after `/project/` in your PostHog address, such as `12345`.\n- **Host:** `eu` for `eu.posthog.com`, `us` for `us.posthog.com`, or your full self-hosted address
|
|
315
|
+
"markdown": "- **Project id:** the number after `/project/` in your PostHog address, such as `12345`.\n- **Host:** `eu` for `eu.posthog.com`, `us` for `us.posthog.com`, or your full self-hosted address, whichever you open the dashboard on."
|
|
316
316
|
},
|
|
317
317
|
{
|
|
318
318
|
"id": "then-run",
|
|
319
319
|
"title": "Then run",
|
|
320
320
|
"kind": "command",
|
|
321
|
-
"markdown": "```sh\nsprid connect posthog --app myapp --key ~/keys/posthog-myapp.txt --project 12345 --host eu\n```\n\
|
|
321
|
+
"markdown": "```sh\nsprid connect posthog --app myapp --key ~/keys/posthog-myapp.txt --project 12345 --host eu\n```\n\nUse your own app slug, file path, project id and host. Add `--workspace <slug>` if needed. Keep the key out of chat."
|
|
322
322
|
},
|
|
323
323
|
{
|
|
324
324
|
"id": "how-to-check-it-worked",
|
|
325
325
|
"title": "How to check it worked",
|
|
326
326
|
"kind": "verify",
|
|
327
|
-
"markdown": "Ask your agent: “Check that Sprid can read recent PostHog events for this app, and confirm the project is correct
|
|
327
|
+
"markdown": "Ask your agent: “Check that Sprid can read recent PostHog events for this app, and confirm the project is correct.” The check reports recent activity or explains why there is none; a saved connection alone does not prove events arrive."
|
|
328
328
|
},
|
|
329
329
|
{
|
|
330
330
|
"id": "metric-definitions",
|
|
331
331
|
"title": "Metric definitions",
|
|
332
332
|
"kind": "detail",
|
|
333
|
-
"markdown": "
|
|
333
|
+
"markdown": "In **Settings → Apps → your app → PostHog**, set the account-created event and the first UTC date from which tracking is complete.\n\n| Metric | What counts |\n|---|---|\n| Registrations | First `sprid_signup` event per PostHog person, across all surfaces |\n| New app users | First native app activity, including anonymous people |\n| Active app users | Distinct people with native activity in the period |\n| Web visitors | Distinct pageview visitors on the saved website hostname |\n\n**Registrations.** Send `sprid_signup` from your server after the account is created, with the account id as `distinct_id`, and identify that id in your clients. Never fire it on login, page load or install. An existing `posthogEvents.signup` mapping also works; `posthogConfig.registration.event` wins over it. No matching event history reads as unavailable; history with no new registrations reads as zero. Periods before the tracking start are unavailable, and comparisons crossing it, or with no confirmed start, are withheld. Backfill with the original creation timestamps.\n\n**App and web.** Native defaults need `posthog-react-native` on iOS, iPadOS or Android and reject explicit web surfaces: set `app_surface: 'web'` on Expo web and `'native'` on devices. Web counts need a browser and exclude reported bots and crawler user agents. Every metric excludes events or people with `is_internal`, `is_test` or `sprid_test = true`. What remains is observed identities, not guaranteed humans.\n\n### Custom properties\n\nAdvanced rules go under **Custom properties**:\n\n```json\n{\"registration\":{\"identity\":{\"scope\":\"event\",\"property\":\"account_id\"}},\"app\":{\"filters\":[{\"scope\":\"event\",\"property\":\"client_type\",\"operator\":\"in\",\"values\":[\"native\"]}]},\"exclude\":[{\"scope\":\"person\",\"property\":\"staff\",\"operator\":\"in\",\"values\":[true]}]}\n```\n\n- `app.filters` replaces SDK/OS matching with your own native rule; all filters must match.\n- `exclude` removes matching traffic from every metric.\n- `registration.filters` narrows the registration event, for example `result = success`.\n- `registration.identity` defaults to `person_id`. A configured property must be present and should never change, because it counts accounts.\n- Each rule takes `scope: event|person`, `operator: in|not_in` and string, number or boolean `values`. A missing property fails `in` and passes `not_in`. Property names are literal keys, dots included.\n\nThe same object is `posthogConfig` in REST `PATCH /api/app-profiles/:id`, MCP `upsert_app_profile` and the App Profile JSON used by `sprid init`, where `registration.event` and `registration.since` also live. No credentials or SQL belong in it. After saving, fetch Insights and check its registration notes and totals against your database before trusting a funnel."
|
|
334
334
|
},
|
|
335
335
|
{
|
|
336
336
|
"id": "review-suspected-automated-traffic",
|
|
337
337
|
"title": "Review suspected automated traffic",
|
|
338
338
|
"kind": "detail",
|
|
339
|
-
"markdown": "
|
|
339
|
+
"markdown": "Read [Check whether a traffic spike is real](https://sprid.studio/docs/traffic) (`sprid docs traffic`) before saving a rule: a spike or a shared fingerprint alone does not prove bots.\n\nOpen **Web visitors → Review traffic exclusions**, or **Settings → Apps → your app → PostHog → Review traffic**. Pick a UTC date range and a traffic group, preview the effect, then save. Agents use MCP `review_traffic` or `POST /api/app-profiles/:ref/traffic-review?workspaceId=…` with `{\"start\":\"2026-09-18\",\"end\":\"2026-09-19\"}`: end dates exclusive, UTC, at most 31 days. An optional `exclusion` previews a rule against this period and the one before. Save approved rules in `posthogConfig.trafficExclusions` through `upsert_app_profile` or the profile PATCH route, keeping the rest of the configuration. Sprid records who edited it and when.\n\nHow exclusions apply:\n\n- App-specific and date-bounded. Properties inside a rule are AND; enabled rules are OR.\n- Applied to website totals, charts, breakdowns, social attribution and weekly website counts, comparison period included. Remaining visitors are recounted as distinct people, never subtracted.\n- Native app activity and registrations are unchanged, and PostHog’s data is never changed or deleted. **Restore this traffic** disables a rule.\n- Raw connected queries and the marketing-review event inventory stay unfiltered as evidence; Insights shows the corrected figures.\n- Only PostHog is supported today."
|
|
340
340
|
},
|
|
341
341
|
{
|
|
342
342
|
"id": "social-traffic-and-clip-comparisons",
|
|
343
343
|
"title": "Social traffic and clip comparisons",
|
|
344
344
|
"kind": "detail",
|
|
345
|
-
"markdown": "Save the app’s website URL on its App Profile as well as
|
|
345
|
+
"markdown": "Save the app’s website URL on its App Profile as well as connecting PostHog. Insights then compares completed-day website sessions with recorded social view gains. Shared bio traffic stays at channel level; only a dedicated tagged link identifies one publish. Older clips with metric activity stay candidates.\n\nCopy the stable bio link and dedicated clip links from Insights. Keep `utm_source`, `utm_medium`, `sprid_account` and, on dedicated links only, `sprid_publish` through any redirects. Never repoint the shared bio link to the newest publish. The optional bio-page HTML export records selections separately and keeps a direct app link; host it on the saved hostname with your existing PostHog setup.\n\nTo capture store-link clicks and website outcomes, add after your PostHog initialization:\n\n```html\n<script src=\"https://sprid.studio/sprid-attribution.js\" defer></script>\n```\n\nIt uses your PostHog client and consent state and sends nothing to Sprid. Call `window.spridAttribution?.track('signup')` or `.track('activation')` only after that action succeeds. `posthogEvents.signup` and `posthogEvents.activation` mappings also count when the event shares the arriving website session. It does not track a native app or join visits to purchases, and a store click is not an install. Missing outcomes stay unmeasured. Redirect-only flows need a beacon before navigating; redirect events are counted apart from sessions. `get_insights` and `sprid insights` return the same evidence as the dashboard."
|
|
346
346
|
},
|
|
347
347
|
{
|
|
348
348
|
"id": "if-it-fails",
|
|
349
349
|
"title": "If it fails",
|
|
350
350
|
"kind": "troubleshooting",
|
|
351
|
-
"markdown": "- **Access denied:** check the key is active, grants your project and has both Read permissions
|
|
352
|
-
},
|
|
353
|
-
{
|
|
354
|
-
"id": "sources-and-verification",
|
|
355
|
-
"title": "Sources and verification",
|
|
356
|
-
"kind": "sources",
|
|
357
|
-
"markdown": "Setup and live data reads checked on 2026-09-09.\n\n- [PostHog personal API keys](https://posthog.com/docs/api/personal-api-keys)\n- [Project identity endpoint](https://posthog.com/docs/api/projects)\n- [HogQL query endpoint](https://posthog.com/docs/api/query)\n- [SDK and framework guides](https://posthog.com/docs/libraries)\n- [React Native screen tracking](https://posthog.com/docs/libraries/react-native)\n- [Identifying users](https://posthog.com/docs/product-analytics/identify)\n- [Funnels](https://posthog.com/docs/product-analytics/funnels)"
|
|
351
|
+
"markdown": "- **Access denied:** check the key is active, grants your project and has both Read permissions. Reconnect with a corrected key file.\n- **Project not found:** check project number and host together. A US project needs the US host.\n- **Connected but no events:** check the dates and project, then ask your agent to check your app’s tracking is sending events."
|
|
358
352
|
},
|
|
359
353
|
{
|
|
360
354
|
"id": "investigate-with-this-connection",
|
|
361
355
|
"title": "Investigate with this connection",
|
|
362
356
|
"kind": "detail",
|
|
363
|
-
"markdown": "
|
|
357
|
+
"markdown": "Reads `query` (HogQL), `events` and `properties` for the pinned project. Check instrumentation before interpreting events. Event-definition discovery also needs `event_definition:read`, property-definition discovery `property_definition:read`, both restricted to the same project.\n\n```sh\nsprid marketing-review capabilities --app <slug> --source posthog --json\n```\n\nSee [connected queries](https://sprid.studio/docs/queries)."
|
|
358
|
+
},
|
|
359
|
+
{
|
|
360
|
+
"id": "sources-and-verification",
|
|
361
|
+
"title": "Sources and verification",
|
|
362
|
+
"kind": "sources",
|
|
363
|
+
"markdown": "Setup and live reads checked 2026-09-09.\n\n- [PostHog personal API keys](https://posthog.com/docs/api/personal-api-keys)\n- [Project identity endpoint](https://posthog.com/docs/api/projects)\n- [HogQL query endpoint](https://posthog.com/docs/api/query)\n- [SDK and framework guides](https://posthog.com/docs/libraries)\n- [React Native screen tracking](https://posthog.com/docs/libraries/react-native)\n- [Identifying users](https://posthog.com/docs/product-analytics/identify)\n- [Funnels](https://posthog.com/docs/product-analytics/funnels)"
|
|
364
364
|
}
|
|
365
365
|
],
|
|
366
|
-
"markdown": "# PostHog\n\n**What Sprid does with this:** See how people use your app and where they stop.\n\n## You need\n\nAccess to your app’s PostHog project and permission to create a **personal API key**. Your app must already send events to PostHog; connecting Sprid does not
|
|
367
|
-
"revision": "
|
|
366
|
+
"markdown": "# PostHog\n\n**What Sprid does with this:** See how people use your app and where they stop.\n\n## You need\n\nAccess to your app’s PostHog project and permission to create a **personal API key**. Your app must already send events to PostHog; connecting Sprid adds no tracking. The public key inside your app does not work here.\n\n## Click path (us.posthog.com or eu.posthog.com)\n\n1. **Settings → Account → Personal API keys → Create personal API key**, named `Sprid <app name>`.\n2. Under access, select **Projects** and choose your app’s project. Leave **All access** off.\n3. Select **Query → Read** and **Project → Read**. Leave write access off.\n4. Copy the key before closing the dialog and save it to a private file such as `~/keys/posthog-myapp.txt`. Use a separate key per app.\n\n## Project id and host\n\n- **Project id:** the number after `/project/` in your PostHog address, such as `12345`.\n- **Host:** `eu` for `eu.posthog.com`, `us` for `us.posthog.com`, or your full self-hosted address, whichever you open the dashboard on.\n\n## Then run\n\n```sh\nsprid connect posthog --app myapp --key ~/keys/posthog-myapp.txt --project 12345 --host eu\n```\n\nUse your own app slug, file path, project id and host. Add `--workspace <slug>` if needed. Keep the key out of chat.\n\n## How to check it worked\n\nAsk your agent: “Check that Sprid can read recent PostHog events for this app, and confirm the project is correct.” The check reports recent activity or explains why there is none; a saved connection alone does not prove events arrive.\n\n## Metric definitions\n\nIn **Settings → Apps → your app → PostHog**, set the account-created event and the first UTC date from which tracking is complete.\n\n| Metric | What counts |\n|---|---|\n| Registrations | First `sprid_signup` event per PostHog person, across all surfaces |\n| New app users | First native app activity, including anonymous people |\n| Active app users | Distinct people with native activity in the period |\n| Web visitors | Distinct pageview visitors on the saved website hostname |\n\n**Registrations.** Send `sprid_signup` from your server after the account is created, with the account id as `distinct_id`, and identify that id in your clients. Never fire it on login, page load or install. An existing `posthogEvents.signup` mapping also works; `posthogConfig.registration.event` wins over it. No matching event history reads as unavailable; history with no new registrations reads as zero. Periods before the tracking start are unavailable, and comparisons crossing it, or with no confirmed start, are withheld. Backfill with the original creation timestamps.\n\n**App and web.** Native defaults need `posthog-react-native` on iOS, iPadOS or Android and reject explicit web surfaces: set `app_surface: 'web'` on Expo web and `'native'` on devices. Web counts need a browser and exclude reported bots and crawler user agents. Every metric excludes events or people with `is_internal`, `is_test` or `sprid_test = true`. What remains is observed identities, not guaranteed humans.\n\n### Custom properties\n\nAdvanced rules go under **Custom properties**:\n\n```json\n{\"registration\":{\"identity\":{\"scope\":\"event\",\"property\":\"account_id\"}},\"app\":{\"filters\":[{\"scope\":\"event\",\"property\":\"client_type\",\"operator\":\"in\",\"values\":[\"native\"]}]},\"exclude\":[{\"scope\":\"person\",\"property\":\"staff\",\"operator\":\"in\",\"values\":[true]}]}\n```\n\n- `app.filters` replaces SDK/OS matching with your own native rule; all filters must match.\n- `exclude` removes matching traffic from every metric.\n- `registration.filters` narrows the registration event, for example `result = success`.\n- `registration.identity` defaults to `person_id`. A configured property must be present and should never change, because it counts accounts.\n- Each rule takes `scope: event|person`, `operator: in|not_in` and string, number or boolean `values`. A missing property fails `in` and passes `not_in`. Property names are literal keys, dots included.\n\nThe same object is `posthogConfig` in REST `PATCH /api/app-profiles/:id`, MCP `upsert_app_profile` and the App Profile JSON used by `sprid init`, where `registration.event` and `registration.since` also live. No credentials or SQL belong in it. After saving, fetch Insights and check its registration notes and totals against your database before trusting a funnel.\n\n## Review suspected automated traffic\n\nRead [Check whether a traffic spike is real](https://sprid.studio/docs/traffic) (`sprid docs traffic`) before saving a rule: a spike or a shared fingerprint alone does not prove bots.\n\nOpen **Web visitors → Review traffic exclusions**, or **Settings → Apps → your app → PostHog → Review traffic**. Pick a UTC date range and a traffic group, preview the effect, then save. Agents use MCP `review_traffic` or `POST /api/app-profiles/:ref/traffic-review?workspaceId=…` with `{\"start\":\"2026-09-18\",\"end\":\"2026-09-19\"}`: end dates exclusive, UTC, at most 31 days. An optional `exclusion` previews a rule against this period and the one before. Save approved rules in `posthogConfig.trafficExclusions` through `upsert_app_profile` or the profile PATCH route, keeping the rest of the configuration. Sprid records who edited it and when.\n\nHow exclusions apply:\n\n- App-specific and date-bounded. Properties inside a rule are AND; enabled rules are OR.\n- Applied to website totals, charts, breakdowns, social attribution and weekly website counts, comparison period included. Remaining visitors are recounted as distinct people, never subtracted.\n- Native app activity and registrations are unchanged, and PostHog’s data is never changed or deleted. **Restore this traffic** disables a rule.\n- Raw connected queries and the marketing-review event inventory stay unfiltered as evidence; Insights shows the corrected figures.\n- Only PostHog is supported today.\n\n## Social traffic and clip comparisons\n\nSave the app’s website URL on its App Profile as well as connecting PostHog. Insights then compares completed-day website sessions with recorded social view gains. Shared bio traffic stays at channel level; only a dedicated tagged link identifies one publish. Older clips with metric activity stay candidates.\n\nCopy the stable bio link and dedicated clip links from Insights. Keep `utm_source`, `utm_medium`, `sprid_account` and, on dedicated links only, `sprid_publish` through any redirects. Never repoint the shared bio link to the newest publish. The optional bio-page HTML export records selections separately and keeps a direct app link; host it on the saved hostname with your existing PostHog setup.\n\nTo capture store-link clicks and website outcomes, add after your PostHog initialization:\n\n```html\n<script src=\"https://sprid.studio/sprid-attribution.js\" defer></script>\n```\n\nIt uses your PostHog client and consent state and sends nothing to Sprid. Call `window.spridAttribution?.track('signup')` or `.track('activation')` only after that action succeeds. `posthogEvents.signup` and `posthogEvents.activation` mappings also count when the event shares the arriving website session. It does not track a native app or join visits to purchases, and a store click is not an install. Missing outcomes stay unmeasured. Redirect-only flows need a beacon before navigating; redirect events are counted apart from sessions. `get_insights` and `sprid insights` return the same evidence as the dashboard.\n\n## If it fails\n\n- **Access denied:** check the key is active, grants your project and has both Read permissions. Reconnect with a corrected key file.\n- **Project not found:** check project number and host together. A US project needs the US host.\n- **Connected but no events:** check the dates and project, then ask your agent to check your app’s tracking is sending events.\n\n## Investigate with this connection\n\nReads `query` (HogQL), `events` and `properties` for the pinned project. Check instrumentation before interpreting events. Event-definition discovery also needs `event_definition:read`, property-definition discovery `property_definition:read`, both restricted to the same project.\n\n```sh\nsprid marketing-review capabilities --app <slug> --source posthog --json\n```\n\nSee [connected queries](https://sprid.studio/docs/queries).\n\n## Sources and verification\n\nSetup and live reads checked 2026-09-09.\n\n- [PostHog personal API keys](https://posthog.com/docs/api/personal-api-keys)\n- [Project identity endpoint](https://posthog.com/docs/api/projects)\n- [HogQL query endpoint](https://posthog.com/docs/api/query)\n- [SDK and framework guides](https://posthog.com/docs/libraries)\n- [React Native screen tracking](https://posthog.com/docs/libraries/react-native)\n- [Identifying users](https://posthog.com/docs/product-analytics/identify)\n- [Funnels](https://posthog.com/docs/product-analytics/funnels)\n",
|
|
367
|
+
"revision": "045b47b5e8256c17"
|
|
368
368
|
},
|
|
369
369
|
{
|
|
370
370
|
"id": "revenuecat",
|
|
@@ -377,59 +377,59 @@ export const GUIDES = [
|
|
|
377
377
|
"id": "you-need",
|
|
378
378
|
"title": "You need",
|
|
379
379
|
"kind": "requirements",
|
|
380
|
-
"markdown": "**Admin** access to the RevenueCat project
|
|
380
|
+
"markdown": "**Admin** access to the RevenueCat project, to create a dedicated **V2 secret API key**. The app’s public key and V1 keys do not work."
|
|
381
381
|
},
|
|
382
382
|
{
|
|
383
383
|
"id": "click-path-apprevenuecatcom",
|
|
384
384
|
"title": "Click path (app.revenuecat.com)",
|
|
385
385
|
"kind": "steps",
|
|
386
|
-
"markdown": "1. Select your project
|
|
386
|
+
"markdown": "1. Select your project → **API keys → Secret API keys → New secret API key**.\n2. Name it `Sprid analytics` and select **V2**.\n3. **Charts metrics permissions**: set **Overview Configuration Access Level** and **Charts Configuration Access Level** to **Read only**.\n4. **Project configuration permissions**: set **Apps Configuration Access Level** to **Read only**. Leave everything else at **No access**.\n5. Click **Generate** and save the key to a private file such as `~/keys/revenuecat-myapp.txt`. Use a separate key per app."
|
|
387
387
|
},
|
|
388
388
|
{
|
|
389
389
|
"id": "project-id",
|
|
390
390
|
"title": "Project id",
|
|
391
391
|
"kind": "identifiers",
|
|
392
|
-
"markdown": "
|
|
392
|
+
"markdown": "**Project settings → General → Project ID**, such as `proj1ab2c3d4`. Not the shorter id in the dashboard address."
|
|
393
393
|
},
|
|
394
394
|
{
|
|
395
395
|
"id": "then-run",
|
|
396
396
|
"title": "Then run",
|
|
397
397
|
"kind": "command",
|
|
398
|
-
"markdown": "```sh\nsprid connect revenuecat --app myapp --key ~/keys/revenuecat-myapp.txt --project proj1ab2c3d4\n```\n\
|
|
398
|
+
"markdown": "```sh\nsprid connect revenuecat --app myapp --key ~/keys/revenuecat-myapp.txt --project proj1ab2c3d4\n```\n\nUse your own app slug, file path and project id. Add `--workspace <slug>` if needed. Keep the key out of chat."
|
|
399
399
|
},
|
|
400
400
|
{
|
|
401
401
|
"id": "how-to-check-it-worked",
|
|
402
402
|
"title": "How to check it worked",
|
|
403
403
|
"kind": "verify",
|
|
404
|
-
"markdown": "Ask your agent: “Check that Sprid can read this app’s RevenueCat overview and daily revenue history. Report any missing dates
|
|
404
|
+
"markdown": "Ask your agent: “Check that Sprid can read this app’s RevenueCat overview and daily revenue history. Report any missing dates.” A saved key alone does not confirm access. The overview can work while history does not; missing dates are not zero sales."
|
|
405
405
|
},
|
|
406
406
|
{
|
|
407
407
|
"id": "if-you-also-sell-on-the-web",
|
|
408
408
|
"title": "If you also sell on the web",
|
|
409
409
|
"kind": "detail",
|
|
410
|
-
"markdown": "Connect services that record
|
|
410
|
+
"markdown": "Connect the services that record the other sales. Sprid withholds a combined total when RevenueCat may already include the same Stripe or Paddle sales, or when currencies or definitions differ. RevenueCat Web Billing and your own Stripe are separate merchant accounts, so they never overlap."
|
|
411
411
|
},
|
|
412
412
|
{
|
|
413
413
|
"id": "if-it-fails",
|
|
414
414
|
"title": "If it fails",
|
|
415
415
|
"kind": "troubleshooting",
|
|
416
|
-
"markdown": "- **Key rejected:** check it is an active V2 secret key for
|
|
417
|
-
},
|
|
418
|
-
{
|
|
419
|
-
"id": "sources-and-verification",
|
|
420
|
-
"title": "Sources and verification",
|
|
421
|
-
"kind": "sources",
|
|
422
|
-
"markdown": "Setup and live data reads checked on 2026-09-09.\n\n- [RevenueCat API keys](https://www.revenuecat.com/docs/projects/authentication)\n- [API V2 reference](https://www.revenuecat.com/docs/api-v2)"
|
|
416
|
+
"markdown": "- **Key rejected:** check it is an active V2 secret key for this project.\n- **Access denied or history missing:** open the key’s **More → Edit**, check all three Read only settings, then **Submit**. No new key needed.\n- **Project not found:** copy the full Project ID from **Project settings → General**. Key and id must belong to the same project.\n- **Too many requests:** retry later. Another key will not help."
|
|
423
417
|
},
|
|
424
418
|
{
|
|
425
419
|
"id": "investigate-with-this-connection",
|
|
426
420
|
"title": "Investigate with this connection",
|
|
427
421
|
"kind": "detail",
|
|
428
|
-
"markdown": "
|
|
422
|
+
"markdown": "Reads `chart_options`, `chart` and `subscriptions` for the pinned project. Read `chart_options` before picking dimensions, filters or resolution, and keep the returned units. `subscriptions` also needs `customer_information:subscriptions:read` and defaults to production; ask for sandbox to see test purchases.\n\n```sh\nsprid marketing-review capabilities --app <slug> --source revenuecat --json\n```\n\nSee [connected queries](https://sprid.studio/docs/queries)."
|
|
423
|
+
},
|
|
424
|
+
{
|
|
425
|
+
"id": "sources-and-verification",
|
|
426
|
+
"title": "Sources and verification",
|
|
427
|
+
"kind": "sources",
|
|
428
|
+
"markdown": "Setup and live reads checked 2026-09-09.\n\n- [RevenueCat API keys](https://www.revenuecat.com/docs/projects/authentication)\n- [API V2 reference](https://www.revenuecat.com/docs/api-v2)"
|
|
429
429
|
}
|
|
430
430
|
],
|
|
431
|
-
"markdown": "# RevenueCat\n\n**What Sprid does with this:** See subscription revenue and how it changes over time.\n\n## You need\n\n**Admin** access to the RevenueCat project
|
|
432
|
-
"revision": "
|
|
431
|
+
"markdown": "# RevenueCat\n\n**What Sprid does with this:** See subscription revenue and how it changes over time.\n\n## You need\n\n**Admin** access to the RevenueCat project, to create a dedicated **V2 secret API key**. The app’s public key and V1 keys do not work.\n\n## Click path (app.revenuecat.com)\n\n1. Select your project → **API keys → Secret API keys → New secret API key**.\n2. Name it `Sprid analytics` and select **V2**.\n3. **Charts metrics permissions**: set **Overview Configuration Access Level** and **Charts Configuration Access Level** to **Read only**.\n4. **Project configuration permissions**: set **Apps Configuration Access Level** to **Read only**. Leave everything else at **No access**.\n5. Click **Generate** and save the key to a private file such as `~/keys/revenuecat-myapp.txt`. Use a separate key per app.\n\n## Project id\n\n**Project settings → General → Project ID**, such as `proj1ab2c3d4`. Not the shorter id in the dashboard address.\n\n## Then run\n\n```sh\nsprid connect revenuecat --app myapp --key ~/keys/revenuecat-myapp.txt --project proj1ab2c3d4\n```\n\nUse your own app slug, file path and project id. Add `--workspace <slug>` if needed. Keep the key out of chat.\n\n## How to check it worked\n\nAsk your agent: “Check that Sprid can read this app’s RevenueCat overview and daily revenue history. Report any missing dates.” A saved key alone does not confirm access. The overview can work while history does not; missing dates are not zero sales.\n\n## If you also sell on the web\n\nConnect the services that record the other sales. Sprid withholds a combined total when RevenueCat may already include the same Stripe or Paddle sales, or when currencies or definitions differ. RevenueCat Web Billing and your own Stripe are separate merchant accounts, so they never overlap.\n\n## If it fails\n\n- **Key rejected:** check it is an active V2 secret key for this project.\n- **Access denied or history missing:** open the key’s **More → Edit**, check all three Read only settings, then **Submit**. No new key needed.\n- **Project not found:** copy the full Project ID from **Project settings → General**. Key and id must belong to the same project.\n- **Too many requests:** retry later. Another key will not help.\n\n## Investigate with this connection\n\nReads `chart_options`, `chart` and `subscriptions` for the pinned project. Read `chart_options` before picking dimensions, filters or resolution, and keep the returned units. `subscriptions` also needs `customer_information:subscriptions:read` and defaults to production; ask for sandbox to see test purchases.\n\n```sh\nsprid marketing-review capabilities --app <slug> --source revenuecat --json\n```\n\nSee [connected queries](https://sprid.studio/docs/queries).\n\n## Sources and verification\n\nSetup and live reads checked 2026-09-09.\n\n- [RevenueCat API keys](https://www.revenuecat.com/docs/projects/authentication)\n- [API V2 reference](https://www.revenuecat.com/docs/api-v2)\n",
|
|
432
|
+
"revision": "69f20ef0200c0d7a"
|
|
433
433
|
},
|
|
434
434
|
{
|
|
435
435
|
"id": "stripe",
|
|
@@ -442,19 +442,19 @@ export const GUIDES = [
|
|
|
442
442
|
"id": "you-need",
|
|
443
443
|
"title": "You need",
|
|
444
444
|
"kind": "requirements",
|
|
445
|
-
"markdown": "Permission to create a **restricted API key** in Stripe
|
|
445
|
+
"markdown": "Permission to create a **restricted API key** in Stripe: live and read-only, beginning with `rk_live_`."
|
|
446
446
|
},
|
|
447
447
|
{
|
|
448
448
|
"id": "click-path-dashboardstripecom",
|
|
449
449
|
"title": "Click path (dashboard.stripe.com)",
|
|
450
450
|
"kind": "steps",
|
|
451
|
-
"markdown": "1. Open [Stripe](https://dashboard.stripe.com) → **Developers → API keys → Restricted keys → Create restricted key
|
|
451
|
+
"markdown": "1. Open [Stripe](https://dashboard.stripe.com) → **Developers → API keys → Restricted keys → Create restricted key**, and name it `Sprid`.\n2. Set these to **Read**:\n - **Core → Charges** and **Account**\n - **Billing → Subscriptions**, **Invoices** and **Prices**\n3. Leave every other permission at **None**.\n4. Create the key and save it to a private file such as `~/keys/stripe-sprid.txt`."
|
|
452
452
|
},
|
|
453
453
|
{
|
|
454
454
|
"id": "then-run",
|
|
455
455
|
"title": "Then run",
|
|
456
456
|
"kind": "command",
|
|
457
|
-
"markdown": "```\nsprid connect stripe --app <slug> --key ~/keys/stripe-sprid.txt\n```\n\
|
|
457
|
+
"markdown": "```\nsprid connect stripe --app <slug> --key ~/keys/stripe-sprid.txt\n```\n\nUse your Sprid app slug and your own file path. Keep the key out of chat."
|
|
458
458
|
},
|
|
459
459
|
{
|
|
460
460
|
"id": "how-to-check-it-worked",
|
|
@@ -466,35 +466,35 @@ export const GUIDES = [
|
|
|
466
466
|
"id": "what-the-numbers-mean",
|
|
467
467
|
"title": "What the numbers mean",
|
|
468
468
|
"kind": "detail",
|
|
469
|
-
"markdown": "MRR
|
|
469
|
+
"markdown": "MRR is current active and past-due subscription prices, with annual plans spread over 12 months. It excludes trials and ignores discounts, proration and tax, so it differs from Stripe’s dashboard. Revenue covers 28 complete calendar days; refunds restate the original charge date. Currencies stay separate."
|
|
470
470
|
},
|
|
471
471
|
{
|
|
472
472
|
"id": "if-you-also-use-revenuecat",
|
|
473
473
|
"title": "If you also use RevenueCat",
|
|
474
474
|
"kind": "detail",
|
|
475
|
-
"markdown": "If RevenueCat may already count these Stripe sales, Sprid withholds the combined total
|
|
475
|
+
"markdown": "If RevenueCat may already count these Stripe sales, Sprid withholds the combined total until the overlap is resolved and currencies and definitions match."
|
|
476
476
|
},
|
|
477
477
|
{
|
|
478
478
|
"id": "if-it-fails",
|
|
479
479
|
"title": "If it fails",
|
|
480
480
|
"kind": "troubleshooting",
|
|
481
|
-
"markdown": "- **Key rejected:** check the copied value is complete and starts with `rk_live_`.\n- **Permission denied:** check
|
|
481
|
+
"markdown": "- **Key rejected:** check the copied value is complete and starts with `rk_live_`.\n- **Permission denied:** check every Read permission above, then reconnect with a corrected key.\n- **MRR is zero but sales appear:** one-off purchases count as revenue, not recurring subscriptions."
|
|
482
|
+
},
|
|
483
|
+
{
|
|
484
|
+
"id": "investigate-with-this-connection",
|
|
485
|
+
"title": "Investigate with this connection",
|
|
486
|
+
"kind": "detail",
|
|
487
|
+
"markdown": "Reads `subscriptions` and `charges` for the key’s merchant account. Filter by price or customer when several products share it. Amounts keep currency and minor units; Stripe SQL and Analytics are not exposed.\n\n```sh\nsprid marketing-review capabilities --app <slug> --source stripe --json\n```\n\nSee [connected queries](https://sprid.studio/docs/queries)."
|
|
482
488
|
},
|
|
483
489
|
{
|
|
484
490
|
"id": "sources",
|
|
485
491
|
"title": "Sources",
|
|
486
492
|
"kind": "sources",
|
|
487
493
|
"markdown": "- [Restricted API keys](https://docs.stripe.com/keys/restricted-api-keys)\n- [Analytics API and its write requirement](https://docs.stripe.com/data/analytics)\n- [Subscriptions and charges](https://docs.stripe.com/api)"
|
|
488
|
-
},
|
|
489
|
-
{
|
|
490
|
-
"id": "investigate-with-this-connection",
|
|
491
|
-
"title": "Investigate with this connection",
|
|
492
|
-
"kind": "detail",
|
|
493
|
-
"markdown": "Your agent can use `list_marketing_queries` and `query_marketing_source` for `subscriptions`, `charges`. Discover the exact parameters and required setup with:\n\n```sh\nsprid marketing-review capabilities --app <slug> --source stripe --json\n```\n\nCredential-scoped merchant account. Filter by price/customer as appropriate when several products share the account. Amounts retain currency and minor units; SQL/Stripe Analytics is not exposed. See [connected queries](https://sprid.studio/docs/queries) for the shared workflow. Extra operations may need additional read permissions; a stored key alone is not live verification."
|
|
494
494
|
}
|
|
495
495
|
],
|
|
496
|
-
"markdown": "# Stripe\n\n**What Sprid does with this:** Read revenue and subscriptions from your Stripe account.\n\n## You need\n\nPermission to create a **restricted API key** in Stripe
|
|
497
|
-
"revision": "
|
|
496
|
+
"markdown": "# Stripe\n\n**What Sprid does with this:** Read revenue and subscriptions from your Stripe account.\n\n## You need\n\nPermission to create a **restricted API key** in Stripe: live and read-only, beginning with `rk_live_`.\n\n## Click path (dashboard.stripe.com)\n\n1. Open [Stripe](https://dashboard.stripe.com) → **Developers → API keys → Restricted keys → Create restricted key**, and name it `Sprid`.\n2. Set these to **Read**:\n - **Core → Charges** and **Account**\n - **Billing → Subscriptions**, **Invoices** and **Prices**\n3. Leave every other permission at **None**.\n4. Create the key and save it to a private file such as `~/keys/stripe-sprid.txt`.\n\n## Then run\n\n```\nsprid connect stripe --app <slug> --key ~/keys/stripe-sprid.txt\n```\n\nUse your Sprid app slug and your own file path. Keep the key out of chat.\n\n## How to check it worked\n\nAsk your agent: “Read this app’s Stripe revenue through Sprid and check that it is the right account.” A saved key alone does not confirm access.\n\n## What the numbers mean\n\nMRR is current active and past-due subscription prices, with annual plans spread over 12 months. It excludes trials and ignores discounts, proration and tax, so it differs from Stripe’s dashboard. Revenue covers 28 complete calendar days; refunds restate the original charge date. Currencies stay separate.\n\n## If you also use RevenueCat\n\nIf RevenueCat may already count these Stripe sales, Sprid withholds the combined total until the overlap is resolved and currencies and definitions match.\n\n## If it fails\n\n- **Key rejected:** check the copied value is complete and starts with `rk_live_`.\n- **Permission denied:** check every Read permission above, then reconnect with a corrected key.\n- **MRR is zero but sales appear:** one-off purchases count as revenue, not recurring subscriptions.\n\n## Investigate with this connection\n\nReads `subscriptions` and `charges` for the key’s merchant account. Filter by price or customer when several products share it. Amounts keep currency and minor units; Stripe SQL and Analytics are not exposed.\n\n```sh\nsprid marketing-review capabilities --app <slug> --source stripe --json\n```\n\nSee [connected queries](https://sprid.studio/docs/queries).\n\n## Sources\n\n- [Restricted API keys](https://docs.stripe.com/keys/restricted-api-keys)\n- [Analytics API and its write requirement](https://docs.stripe.com/data/analytics)\n- [Subscriptions and charges](https://docs.stripe.com/api)\n",
|
|
497
|
+
"revision": "28709aaf752334aa"
|
|
498
498
|
},
|
|
499
499
|
{
|
|
500
500
|
"id": "polar",
|
|
@@ -513,13 +513,13 @@ export const GUIDES = [
|
|
|
513
513
|
"id": "click-path-polarsh",
|
|
514
514
|
"title": "Click path (polar.sh)",
|
|
515
515
|
"kind": "steps",
|
|
516
|
-
"markdown": "1. Open your organization → **Settings → Developers
|
|
516
|
+
"markdown": "1. Open your organization → **Settings → Developers → New Organization Access Token**, and name it `Sprid`.\n2. Select **metrics:read** only.\n3. Create the token and save it to a private file such as `~/keys/polar-sprid.txt`. It is shown once."
|
|
517
517
|
},
|
|
518
518
|
{
|
|
519
519
|
"id": "then-run",
|
|
520
520
|
"title": "Then run",
|
|
521
521
|
"kind": "command",
|
|
522
|
-
"markdown": "```\nsprid connect polar --app <slug> --key ~/keys/polar-sprid.txt\n```\n\
|
|
522
|
+
"markdown": "```\nsprid connect polar --app <slug> --key ~/keys/polar-sprid.txt\n```\n\nUse your Sprid app slug and your own file path. A personal token covering several organizations also needs `--org <organization-id>`."
|
|
523
523
|
},
|
|
524
524
|
{
|
|
525
525
|
"id": "how-to-check-it-worked",
|
|
@@ -531,29 +531,29 @@ export const GUIDES = [
|
|
|
531
531
|
"id": "what-the-numbers-mean",
|
|
532
532
|
"title": "What the numbers mean",
|
|
533
533
|
"kind": "detail",
|
|
534
|
-
"markdown": "
|
|
534
|
+
"markdown": "Polar’s daily revenue and current monthly recurring revenue. Polar supplies no trial count, so that field stays blank."
|
|
535
535
|
},
|
|
536
536
|
{
|
|
537
537
|
"id": "if-it-fails",
|
|
538
538
|
"title": "If it fails",
|
|
539
539
|
"kind": "troubleshooting",
|
|
540
|
-
"markdown": "- **Access denied:** create a replacement token with **metrics:read**, then reconnect.\n- **Wrong or empty results with a personal token:** add `--org <organization-id
|
|
540
|
+
"markdown": "- **Access denied:** create a replacement token with **metrics:read**, then reconnect.\n- **Wrong or empty results with a personal token:** add `--org <organization-id>`."
|
|
541
|
+
},
|
|
542
|
+
{
|
|
543
|
+
"id": "investigate-with-this-connection",
|
|
544
|
+
"title": "Investigate with this connection",
|
|
545
|
+
"kind": "detail",
|
|
546
|
+
"markdown": "Reads `metrics`, `orders` and `subscriptions` for the pinned organization. Product filters separate apps sold through the same organization.\n\n```sh\nsprid marketing-review capabilities --app <slug> --source polar --json\n```\n\nSee [connected queries](https://sprid.studio/docs/queries)."
|
|
541
547
|
},
|
|
542
548
|
{
|
|
543
549
|
"id": "sources",
|
|
544
550
|
"title": "Sources",
|
|
545
551
|
"kind": "sources",
|
|
546
552
|
"markdown": "- [Metrics endpoint](https://polar.sh/docs/api-reference/metrics/get)"
|
|
547
|
-
},
|
|
548
|
-
{
|
|
549
|
-
"id": "investigate-with-this-connection",
|
|
550
|
-
"title": "Investigate with this connection",
|
|
551
|
-
"kind": "detail",
|
|
552
|
-
"markdown": "Your agent can use `list_marketing_queries` and `query_marketing_source` for `metrics`, `orders`, `subscriptions`. Discover the exact parameters and required setup with:\n\n```sh\nsprid marketing-review capabilities --app <slug> --source polar --json\n```\n\nPinned organization. Product filters distinguish apps sold through the same organization. See [connected queries](https://sprid.studio/docs/queries) for the shared workflow. Extra operations may need additional read permissions; a stored key alone is not live verification."
|
|
553
553
|
}
|
|
554
554
|
],
|
|
555
|
-
"markdown": "# Polar\n\n**What Sprid does with this:** Read revenue and subscriptions from your Polar account.\n\n## You need\n\nAccess to your Polar organization’s developer settings.\n\n## Click path (polar.sh)\n\n1. Open your organization → **Settings → Developers
|
|
556
|
-
"revision": "
|
|
555
|
+
"markdown": "# Polar\n\n**What Sprid does with this:** Read revenue and subscriptions from your Polar account.\n\n## You need\n\nAccess to your Polar organization’s developer settings.\n\n## Click path (polar.sh)\n\n1. Open your organization → **Settings → Developers → New Organization Access Token**, and name it `Sprid`.\n2. Select **metrics:read** only.\n3. Create the token and save it to a private file such as `~/keys/polar-sprid.txt`. It is shown once.\n\n## Then run\n\n```\nsprid connect polar --app <slug> --key ~/keys/polar-sprid.txt\n```\n\nUse your Sprid app slug and your own file path. A personal token covering several organizations also needs `--org <organization-id>`.\n\n## How to check it worked\n\nAsk your agent: “Check that Sprid can read revenue and subscriptions for this Polar organization.” A saved token alone does not confirm access.\n\n## What the numbers mean\n\nPolar’s daily revenue and current monthly recurring revenue. Polar supplies no trial count, so that field stays blank.\n\n## If it fails\n\n- **Access denied:** create a replacement token with **metrics:read**, then reconnect.\n- **Wrong or empty results with a personal token:** add `--org <organization-id>`.\n\n## Investigate with this connection\n\nReads `metrics`, `orders` and `subscriptions` for the pinned organization. Product filters separate apps sold through the same organization.\n\n```sh\nsprid marketing-review capabilities --app <slug> --source polar --json\n```\n\nSee [connected queries](https://sprid.studio/docs/queries).\n\n## Sources\n\n- [Metrics endpoint](https://polar.sh/docs/api-reference/metrics/get)\n",
|
|
556
|
+
"revision": "c5764131bc3591a9"
|
|
557
557
|
},
|
|
558
558
|
{
|
|
559
559
|
"id": "lemonsqueezy",
|
|
@@ -572,13 +572,13 @@ export const GUIDES = [
|
|
|
572
572
|
"id": "click-path-applemonsqueezycom",
|
|
573
573
|
"title": "Click path (app.lemonsqueezy.com)",
|
|
574
574
|
"kind": "steps",
|
|
575
|
-
"markdown": "1.
|
|
575
|
+
"markdown": "1. **Settings → API**: click **+** and name the key `Sprid`.\n2. Save the key to a private file such as `~/keys/lemonsqueezy-sprid.txt`. It is shown once.\n3. **Settings → Stores**: select your store and copy its numeric id from the page address."
|
|
576
576
|
},
|
|
577
577
|
{
|
|
578
578
|
"id": "then-run",
|
|
579
579
|
"title": "Then run",
|
|
580
580
|
"kind": "command",
|
|
581
|
-
"markdown": "```\nsprid connect lemonsqueezy --app <slug> --key ~/keys/lemonsqueezy-sprid.txt --store 12345\n```\n\
|
|
581
|
+
"markdown": "```\nsprid connect lemonsqueezy --app <slug> --key ~/keys/lemonsqueezy-sprid.txt --store 12345\n```\n\nUse your Sprid app slug, your own file path and your store id. Both `--key` and `--store` are required."
|
|
582
582
|
},
|
|
583
583
|
{
|
|
584
584
|
"id": "how-to-check-it-worked",
|
|
@@ -590,29 +590,29 @@ export const GUIDES = [
|
|
|
590
590
|
"id": "what-the-numbers-mean",
|
|
591
591
|
"title": "What the numbers mean",
|
|
592
592
|
"kind": "detail",
|
|
593
|
-
"markdown": "Revenue covers 28 complete calendar days
|
|
593
|
+
"markdown": "Revenue covers 28 complete calendar days: orders plus renewal and update invoices, without duplicate initial invoices, with refunds deducted on the original purchase date. Currencies stay separate. Incomplete pagination makes the total unavailable.\n\nMRR stays unavailable until a complete priced billing schedule exists, because subscriptions carry price IDs, not prices."
|
|
594
594
|
},
|
|
595
595
|
{
|
|
596
596
|
"id": "if-it-fails",
|
|
597
597
|
"title": "If it fails",
|
|
598
598
|
"kind": "troubleshooting",
|
|
599
|
-
"markdown": "- **Key rejected:** create a replacement and reconnect.\n- **Store not found:** check the store id belongs to the account that created the key.\n- **An unexpected error page appears:** retry
|
|
599
|
+
"markdown": "- **Key rejected:** create a replacement and reconnect.\n- **Store not found:** check the store id belongs to the account that created the key.\n- **An unexpected error page appears:** retry. If it persists, send the message to [Sprid support](mailto:hello@sprid.studio)."
|
|
600
|
+
},
|
|
601
|
+
{
|
|
602
|
+
"id": "investigate-with-this-connection",
|
|
603
|
+
"title": "Investigate with this connection",
|
|
604
|
+
"kind": "detail",
|
|
605
|
+
"markdown": "Reads `orders`, `subscriptions` and `subscription-invoices` for the pinned store. Product and variant filters separate apps in the same store.\n\n```sh\nsprid marketing-review capabilities --app <slug> --source lemonsqueezy --json\n```\n\nSee [connected queries](https://sprid.studio/docs/queries)."
|
|
600
606
|
},
|
|
601
607
|
{
|
|
602
608
|
"id": "sources",
|
|
603
609
|
"title": "Sources",
|
|
604
610
|
"kind": "sources",
|
|
605
611
|
"markdown": "- [The store object](https://docs.lemonsqueezy.com/api/stores/the-store-object)\n- [Getting started with the API](https://docs.lemonsqueezy.com/guides/developer-guide/getting-started)"
|
|
606
|
-
},
|
|
607
|
-
{
|
|
608
|
-
"id": "investigate-with-this-connection",
|
|
609
|
-
"title": "Investigate with this connection",
|
|
610
|
-
"kind": "detail",
|
|
611
|
-
"markdown": "Your agent can use `list_marketing_queries` and `query_marketing_source` for `orders`, `subscriptions` and `subscription-invoices`. Discover the exact parameters and required setup with:\n\n```sh\nsprid marketing-review capabilities --app <slug> --source lemonsqueezy --json\n```\n\nPinned store. Product/variant filters distinguish apps in the same store. Preserve provider amounts and currencies. See [connected queries](https://sprid.studio/docs/queries) for the shared workflow. Extra operations may need additional read permissions; a stored key alone is not live verification."
|
|
612
612
|
}
|
|
613
613
|
],
|
|
614
|
-
"markdown": "# Lemon Squeezy\n\n**What Sprid does with this:** Read sales and subscriptions from your Lemon Squeezy store.\n\n## You need\n\nAccess to your store’s **Settings → API** page.\n\n## Click path (app.lemonsqueezy.com)\n\n1.
|
|
615
|
-
"revision": "
|
|
614
|
+
"markdown": "# Lemon Squeezy\n\n**What Sprid does with this:** Read sales and subscriptions from your Lemon Squeezy store.\n\n## You need\n\nAccess to your store’s **Settings → API** page.\n\n## Click path (app.lemonsqueezy.com)\n\n1. **Settings → API**: click **+** and name the key `Sprid`.\n2. Save the key to a private file such as `~/keys/lemonsqueezy-sprid.txt`. It is shown once.\n3. **Settings → Stores**: select your store and copy its numeric id from the page address.\n\n## Then run\n\n```\nsprid connect lemonsqueezy --app <slug> --key ~/keys/lemonsqueezy-sprid.txt --store 12345\n```\n\nUse your Sprid app slug, your own file path and your store id. Both `--key` and `--store` are required.\n\n## How to check it worked\n\nAsk your agent: “Read this store’s Lemon Squeezy sales through Sprid and confirm the store is correct.” A saved key alone does not confirm access.\n\n## What the numbers mean\n\nRevenue covers 28 complete calendar days: orders plus renewal and update invoices, without duplicate initial invoices, with refunds deducted on the original purchase date. Currencies stay separate. Incomplete pagination makes the total unavailable.\n\nMRR stays unavailable until a complete priced billing schedule exists, because subscriptions carry price IDs, not prices.\n\n## If it fails\n\n- **Key rejected:** create a replacement and reconnect.\n- **Store not found:** check the store id belongs to the account that created the key.\n- **An unexpected error page appears:** retry. If it persists, send the message to [Sprid support](mailto:hello@sprid.studio).\n\n## Investigate with this connection\n\nReads `orders`, `subscriptions` and `subscription-invoices` for the pinned store. Product and variant filters separate apps in the same store.\n\n```sh\nsprid marketing-review capabilities --app <slug> --source lemonsqueezy --json\n```\n\nSee [connected queries](https://sprid.studio/docs/queries).\n\n## Sources\n\n- [The store object](https://docs.lemonsqueezy.com/api/stores/the-store-object)\n- [Getting started with the API](https://docs.lemonsqueezy.com/guides/developer-guide/getting-started)\n",
|
|
615
|
+
"revision": "0554f12559c62444"
|
|
616
616
|
},
|
|
617
617
|
{
|
|
618
618
|
"id": "paddle",
|
|
@@ -625,19 +625,19 @@ export const GUIDES = [
|
|
|
625
625
|
"id": "you-need",
|
|
626
626
|
"title": "You need",
|
|
627
627
|
"kind": "requirements",
|
|
628
|
-
"markdown": "
|
|
628
|
+
"markdown": "**Paddle Billing** access (Paddle Classic keys do not work), and whether the key is for your live account or sandbox."
|
|
629
629
|
},
|
|
630
630
|
{
|
|
631
631
|
"id": "click-path-vendorspaddlecom",
|
|
632
632
|
"title": "Click path (vendors.paddle.com)",
|
|
633
633
|
"kind": "steps",
|
|
634
|
-
"markdown": "1.
|
|
634
|
+
"markdown": "1. **Developer tools → Authentication → New API key**, named `Sprid`.\n2. Select **transaction.read** and **subscription.read** only.\n3. Create the key and save it to a private file such as `~/keys/paddle-sprid.txt`. It is shown once."
|
|
635
635
|
},
|
|
636
636
|
{
|
|
637
637
|
"id": "then-run",
|
|
638
638
|
"title": "Then run",
|
|
639
639
|
"kind": "command",
|
|
640
|
-
"markdown": "```\nsprid connect paddle --app <slug> --key ~/keys/paddle-sprid.txt\n```\n\
|
|
640
|
+
"markdown": "```\nsprid connect paddle --app <slug> --key ~/keys/paddle-sprid.txt\n```\n\nUse your Sprid app slug and your own file path. Add `--env sandbox` for a sandbox key."
|
|
641
641
|
},
|
|
642
642
|
{
|
|
643
643
|
"id": "how-to-check-it-worked",
|
|
@@ -649,29 +649,29 @@ export const GUIDES = [
|
|
|
649
649
|
"id": "what-the-numbers-mean",
|
|
650
650
|
"title": "What the numbers mean",
|
|
651
651
|
"kind": "detail",
|
|
652
|
-
"markdown": "Revenue covers 28 complete days of gross completed transactions
|
|
652
|
+
"markdown": "Revenue covers 28 complete days of gross completed transactions: tax included, before refunds, credits, chargebacks and Paddle’s fees, so it will exceed your payout. MRR is current active subscription prices over their billing periods. Currencies stay separate; incomplete pagination makes a total unavailable."
|
|
653
653
|
},
|
|
654
654
|
{
|
|
655
655
|
"id": "if-it-fails",
|
|
656
656
|
"title": "If it fails",
|
|
657
657
|
"kind": "troubleshooting",
|
|
658
|
-
"markdown": "- **Access denied:**
|
|
658
|
+
"markdown": "- **Access denied:** a sandbox key needs `--env sandbox`.\n- **A permission is missing:** create a replacement key with both permissions, then reconnect.\n- **Revenue exceeds your payout:** expected. Compare against customer payments, not what is left after tax and fees."
|
|
659
|
+
},
|
|
660
|
+
{
|
|
661
|
+
"id": "investigate-with-this-connection",
|
|
662
|
+
"title": "Investigate with this connection",
|
|
663
|
+
"kind": "detail",
|
|
664
|
+
"markdown": "Reads `transactions` and `subscriptions` for the key’s merchant account, live or sandbox as saved. Amounts are minor-unit strings. Subscription creation-date filters apply per page, so keep paginating past pages with no matches.\n\n```sh\nsprid marketing-review capabilities --app <slug> --source paddle --json\n```\n\nSee [connected queries](https://sprid.studio/docs/queries)."
|
|
659
665
|
},
|
|
660
666
|
{
|
|
661
667
|
"id": "sources",
|
|
662
668
|
"title": "Sources",
|
|
663
669
|
"kind": "sources",
|
|
664
670
|
"markdown": "- [List transactions](https://developer.paddle.com/api-reference/transactions/list-transactions)\n- [API authentication](https://developer.paddle.com/api-reference/about/authentication)"
|
|
665
|
-
},
|
|
666
|
-
{
|
|
667
|
-
"id": "investigate-with-this-connection",
|
|
668
|
-
"title": "Investigate with this connection",
|
|
669
|
-
"kind": "detail",
|
|
670
|
-
"markdown": "Your agent can use `list_marketing_queries` and `query_marketing_source` for `transactions`, `subscriptions`. Discover the exact parameters and required setup with:\n\n```sh\nsprid marketing-review capabilities --app <slug> --source paddle --json\n```\n\nCredential-scoped merchant account, with sandbox/live from the profile. Dates filter billed or created time as described; monetary values are minor-unit strings. See [connected queries](https://sprid.studio/docs/queries) for the shared workflow. Extra operations may need additional read permissions; a stored key alone is not live verification.\n\nSubscription investigations need `subscription.read` in addition to `transaction.read` for transaction pages. Creation-date filtering on subscriptions happens per page in Sprid; continue pagination even if a page contains no matches."
|
|
671
671
|
}
|
|
672
672
|
],
|
|
673
|
-
"markdown": "# Paddle\n\n**What Sprid does with this:** Read revenue and subscriptions from your Paddle account.\n\n## You need\n\
|
|
674
|
-
"revision": "
|
|
673
|
+
"markdown": "# Paddle\n\n**What Sprid does with this:** Read revenue and subscriptions from your Paddle account.\n\n## You need\n\n**Paddle Billing** access (Paddle Classic keys do not work), and whether the key is for your live account or sandbox.\n\n## Click path (vendors.paddle.com)\n\n1. **Developer tools → Authentication → New API key**, named `Sprid`.\n2. Select **transaction.read** and **subscription.read** only.\n3. Create the key and save it to a private file such as `~/keys/paddle-sprid.txt`. It is shown once.\n\n## Then run\n\n```\nsprid connect paddle --app <slug> --key ~/keys/paddle-sprid.txt\n```\n\nUse your Sprid app slug and your own file path. Add `--env sandbox` for a sandbox key.\n\n## How to check it worked\n\nAsk your agent: “Check that Sprid can read this Paddle account’s completed sales and active subscriptions.” A saved key alone does not confirm access.\n\n## What the numbers mean\n\nRevenue covers 28 complete days of gross completed transactions: tax included, before refunds, credits, chargebacks and Paddle’s fees, so it will exceed your payout. MRR is current active subscription prices over their billing periods. Currencies stay separate; incomplete pagination makes a total unavailable.\n\n## If it fails\n\n- **Access denied:** a sandbox key needs `--env sandbox`.\n- **A permission is missing:** create a replacement key with both permissions, then reconnect.\n- **Revenue exceeds your payout:** expected. Compare against customer payments, not what is left after tax and fees.\n\n## Investigate with this connection\n\nReads `transactions` and `subscriptions` for the key’s merchant account, live or sandbox as saved. Amounts are minor-unit strings. Subscription creation-date filters apply per page, so keep paginating past pages with no matches.\n\n```sh\nsprid marketing-review capabilities --app <slug> --source paddle --json\n```\n\nSee [connected queries](https://sprid.studio/docs/queries).\n\n## Sources\n\n- [List transactions](https://developer.paddle.com/api-reference/transactions/list-transactions)\n- [API authentication](https://developer.paddle.com/api-reference/about/authentication)\n",
|
|
674
|
+
"revision": "f02048423594cb56"
|
|
675
675
|
},
|
|
676
676
|
{
|
|
677
677
|
"id": "cloudflare",
|
|
@@ -690,53 +690,47 @@ export const GUIDES = [
|
|
|
690
690
|
"id": "click-path-dashcloudflarecom",
|
|
691
691
|
"title": "Click path (dash.cloudflare.com)",
|
|
692
692
|
"kind": "steps",
|
|
693
|
-
"markdown": "1. Open [Cloudflare](https://dash.cloudflare.com) →
|
|
693
|
+
"markdown": "1. Open [Cloudflare](https://dash.cloudflare.com) → profile icon → **My Profile → API Tokens**.\n2. **Create Token → Custom token → Get started**, named `Sprid`.\n3. **Permissions**:\n - **Zone → Analytics → Read**\n - **Account → Account Analytics → Read**\n4. **Zone Resources → Include → Specific zone**: your domain.\n5. **Account Resources → Include**: your account.\n6. Leave **Client IP Address Filtering** and **TTL** empty. **Continue to summary → Create Token**.\n7. Save the token to a private file such as `~/keys/cloudflare-sprid.txt`. It is shown once.\n\nFor a connection that survives you leaving the team, create an account-owned token instead under **Manage Account → Account API Tokens**, with the same permissions."
|
|
694
694
|
},
|
|
695
695
|
{
|
|
696
696
|
"id": "zone-id",
|
|
697
697
|
"title": "Zone id",
|
|
698
698
|
"kind": "identifiers",
|
|
699
|
-
"markdown": "
|
|
699
|
+
"markdown": "Your domain → **Overview** → **API** card: copy **Zone ID** and **Account ID**. The Zone ID goes in the command; ask your agent to save the Account ID in your Sprid app profile."
|
|
700
700
|
},
|
|
701
701
|
{
|
|
702
702
|
"id": "then-run",
|
|
703
703
|
"title": "Then run",
|
|
704
704
|
"kind": "command",
|
|
705
|
-
"markdown": "```\nsprid connect cloudflare --token ~/keys/cloudflare-sprid.txt --zone 0123456789abcdef0123456789abcdef\n```\n\
|
|
705
|
+
"markdown": "```\nsprid connect cloudflare --token ~/keys/cloudflare-sprid.txt --zone 0123456789abcdef0123456789abcdef\n```\n\nUse your own file path and Zone ID. Keep the token out of chat."
|
|
706
706
|
},
|
|
707
707
|
{
|
|
708
708
|
"id": "how-to-check-it-worked",
|
|
709
709
|
"title": "How to check it worked",
|
|
710
710
|
"kind": "verify",
|
|
711
|
-
"markdown": "Run `sprid status`, then ask your agent: “Check that Sprid can read recent Cloudflare traffic for this domain
|
|
711
|
+
"markdown": "Run `sprid status`, then ask your agent: “Check that Sprid can read recent Cloudflare traffic for this domain.” The check names the domain and says whether visitor reports or only request counts are available."
|
|
712
712
|
},
|
|
713
713
|
{
|
|
714
714
|
"id": "if-it-fails",
|
|
715
715
|
"title": "If it fails",
|
|
716
716
|
"kind": "troubleshooting",
|
|
717
|
-
"markdown": "- **Access denied:**
|
|
717
|
+
"markdown": "- **Access denied:** **API Tokens → ⋯ → Edit**. Check both Read permissions and the selected domain and account.\n- **Domain not found:** use the Zone ID, not the domain name.\n- **Visitor reports are empty:** enable **Analytics & Logs → Web Analytics** and check the tracking snippet is on your site."
|
|
718
718
|
},
|
|
719
719
|
{
|
|
720
|
-
"id": "
|
|
721
|
-
"title": "
|
|
720
|
+
"id": "investigate-with-this-connection",
|
|
721
|
+
"title": "Investigate with this connection",
|
|
722
722
|
"kind": "detail",
|
|
723
|
-
"markdown": "
|
|
723
|
+
"markdown": "Reads `rum` and `http`. RUM is pinned to the saved account and hostname; beacon traffic is sampled and not verified human.\n\n```sh\nsprid marketing-review capabilities --app <slug> --source cloudflare --json\n```\n\nSee [connected queries](https://sprid.studio/docs/queries)."
|
|
724
724
|
},
|
|
725
725
|
{
|
|
726
726
|
"id": "sources",
|
|
727
727
|
"title": "Sources",
|
|
728
728
|
"kind": "sources",
|
|
729
729
|
"markdown": "- [Create an API token](https://developers.cloudflare.com/fundamentals/api/get-started/create-token/)\n- [GraphQL Analytics API token permissions](https://developers.cloudflare.com/analytics/graphql-api/getting-started/authentication/api-token-auth/)\n- [Find zone and account ids](https://developers.cloudflare.com/fundamentals/account/find-account-and-zone-ids/)\n- [Verify a token](https://developers.cloudflare.com/api/resources/user/subresources/tokens/methods/verify/)"
|
|
730
|
-
},
|
|
731
|
-
{
|
|
732
|
-
"id": "investigate-with-this-connection",
|
|
733
|
-
"title": "Investigate with this connection",
|
|
734
|
-
"kind": "detail",
|
|
735
|
-
"markdown": "Your agent can use `list_marketing_queries` and `query_marketing_source` for `rum`, `http`. Discover the exact parameters and required setup with:\n\n```sh\nsprid marketing-review capabilities --app <slug> --source cloudflare --json\n```\n\nRUM is pinned to the saved account and website hostname. Beacon traffic is sampled and is not verified human traffic. See [connected queries](https://sprid.studio/docs/queries) for the shared workflow. Extra operations may need additional read permissions; a stored key alone is not live verification."
|
|
736
730
|
}
|
|
737
731
|
],
|
|
738
|
-
"markdown": "# Cloudflare (optional)\n\n**What Sprid does with this:** Read traffic reports for your website.\n\n## You need\n\nAccess to your domain’s Cloudflare account and permission to create a token. Enable **Web Analytics** for visitor reports; basic request counts include bots.\n\n## Click path (dash.cloudflare.com)\n\n1. Open [Cloudflare](https://dash.cloudflare.com) →
|
|
739
|
-
"revision": "
|
|
732
|
+
"markdown": "# Cloudflare (optional)\n\n**What Sprid does with this:** Read traffic reports for your website.\n\n## You need\n\nAccess to your domain’s Cloudflare account and permission to create a token. Enable **Web Analytics** for visitor reports; basic request counts include bots.\n\n## Click path (dash.cloudflare.com)\n\n1. Open [Cloudflare](https://dash.cloudflare.com) → profile icon → **My Profile → API Tokens**.\n2. **Create Token → Custom token → Get started**, named `Sprid`.\n3. **Permissions**:\n - **Zone → Analytics → Read**\n - **Account → Account Analytics → Read**\n4. **Zone Resources → Include → Specific zone**: your domain.\n5. **Account Resources → Include**: your account.\n6. Leave **Client IP Address Filtering** and **TTL** empty. **Continue to summary → Create Token**.\n7. Save the token to a private file such as `~/keys/cloudflare-sprid.txt`. It is shown once.\n\nFor a connection that survives you leaving the team, create an account-owned token instead under **Manage Account → Account API Tokens**, with the same permissions.\n\n## Zone id\n\nYour domain → **Overview** → **API** card: copy **Zone ID** and **Account ID**. The Zone ID goes in the command; ask your agent to save the Account ID in your Sprid app profile.\n\n## Then run\n\n```\nsprid connect cloudflare --token ~/keys/cloudflare-sprid.txt --zone 0123456789abcdef0123456789abcdef\n```\n\nUse your own file path and Zone ID. Keep the token out of chat.\n\n## How to check it worked\n\nRun `sprid status`, then ask your agent: “Check that Sprid can read recent Cloudflare traffic for this domain.” The check names the domain and says whether visitor reports or only request counts are available.\n\n## If it fails\n\n- **Access denied:** **API Tokens → ⋯ → Edit**. Check both Read permissions and the selected domain and account.\n- **Domain not found:** use the Zone ID, not the domain name.\n- **Visitor reports are empty:** enable **Analytics & Logs → Web Analytics** and check the tracking snippet is on your site.\n\n## Investigate with this connection\n\nReads `rum` and `http`. RUM is pinned to the saved account and hostname; beacon traffic is sampled and not verified human.\n\n```sh\nsprid marketing-review capabilities --app <slug> --source cloudflare --json\n```\n\nSee [connected queries](https://sprid.studio/docs/queries).\n\n## Sources\n\n- [Create an API token](https://developers.cloudflare.com/fundamentals/api/get-started/create-token/)\n- [GraphQL Analytics API token permissions](https://developers.cloudflare.com/analytics/graphql-api/getting-started/authentication/api-token-auth/)\n- [Find zone and account ids](https://developers.cloudflare.com/fundamentals/account/find-account-and-zone-ids/)\n- [Verify a token](https://developers.cloudflare.com/api/resources/user/subresources/tokens/methods/verify/)\n",
|
|
733
|
+
"revision": "0465290022d3254f"
|
|
740
734
|
},
|
|
741
735
|
{
|
|
742
736
|
"id": "instagram",
|
|
@@ -749,47 +743,47 @@ export const GUIDES = [
|
|
|
749
743
|
"id": "you-need",
|
|
750
744
|
"title": "You need",
|
|
751
745
|
"kind": "requirements",
|
|
752
|
-
"markdown": "
|
|
746
|
+
"markdown": "- An Instagram **Business** or **Creator** account. A Facebook Page is optional. No account yet? Start with [Create your social accounts](https://sprid.studio/docs/connect/social-accounts).\n- Your phone for any two-factor prompt.\n\nTo switch a personal account: profile → **≡ → Settings and activity → For professionals → Account type and tools → Switch to professional account** → pick a category → **Creator** or **Business**. You can skip linking a Facebook Page."
|
|
753
747
|
},
|
|
754
748
|
{
|
|
755
749
|
"id": "then-run",
|
|
756
750
|
"title": "Then run",
|
|
757
751
|
"kind": "command",
|
|
758
|
-
"markdown": "```\nsprid connect instagram --account <slug>\n```\n\nReplace `<slug>` with your Sprid account slug
|
|
752
|
+
"markdown": "```\nsprid connect instagram --account <slug>\n```\n\nReplace `<slug>` with your Sprid account slug, or use **Settings → Channels → Connect Instagram** in Sprid. In an agent-controlled browser, add `--no-browser` and open the returned link in the session for the intended account. Keep that link private."
|
|
759
753
|
},
|
|
760
754
|
{
|
|
761
755
|
"id": "click-path-the-connect",
|
|
762
756
|
"title": "Click path (the connect)",
|
|
763
757
|
"kind": "steps",
|
|
764
|
-
"markdown": "1.
|
|
758
|
+
"markdown": "1. Sign in to the Instagram account you want. If another account is signed in, sign out first.\n2. Check the handle in the consent dialog and leave the requested permissions enabled.\n3. Click **Allow** to return to Sprid."
|
|
765
759
|
},
|
|
766
760
|
{
|
|
767
761
|
"id": "how-to-check-it-worked",
|
|
768
762
|
"title": "How to check it worked",
|
|
769
763
|
"kind": "verify",
|
|
770
|
-
"markdown": "Run `sprid status` and check that Instagram shows the right handle
|
|
764
|
+
"markdown": "Run `sprid status` and check that Instagram shows the right handle. Before scheduling a batch, publish one reviewed post and check it on Instagram."
|
|
771
765
|
},
|
|
772
766
|
{
|
|
773
767
|
"id": "if-it-fails",
|
|
774
768
|
"title": "If it fails",
|
|
775
769
|
"kind": "troubleshooting",
|
|
776
|
-
"markdown": "- **Account not eligible:** switch to Business or Creator, then reconnect.\n- **Already connected elsewhere:**
|
|
770
|
+
"markdown": "- **Account not eligible:** switch to Business or Creator, then reconnect.\n- **Already connected elsewhere:** check the handle. If the wrong account was signed in, cancel and restart. Move a connection only if you mean to change its Sprid destination.\n- **Connection expired or permissions missing:** run the connect command again and approve all requested access.\n- **App unavailable, “Invalid Scopes” or a redirect error:** send the error to [Sprid support](mailto:hello@sprid.studio). Only Sprid can fix these.\n- **Long-lived token exchange fails after Allow:** authorization did not complete. Send the error text to [Sprid support](mailto:hello@sprid.studio). If Sprid invites your account as a tester, open Instagram **Settings → Website permissions → Apps and websites → Tester Invites**, accept Sprid-IG, then start a fresh connection. The tab may only appear after an invitation. Do not create another Instagram account or your own Meta developer app. `Unsupported request - method type: get` alone does not identify the cause."
|
|
771
|
+
},
|
|
772
|
+
{
|
|
773
|
+
"id": "investigate-with-this-connection",
|
|
774
|
+
"title": "Investigate with this connection",
|
|
775
|
+
"kind": "detail",
|
|
776
|
+
"markdown": "Operations `posts` and `comments`, read from Sprid’s stored publishes, metric snapshots and inbox (no live platform read; missing metrics are unmeasured, not zero).\n\n```sh\nsprid marketing-review capabilities --app <slug> --source instagram --json\n```\n\nSee [connected queries](https://sprid.studio/docs/queries)."
|
|
777
777
|
},
|
|
778
778
|
{
|
|
779
779
|
"id": "sources",
|
|
780
780
|
"title": "Sources",
|
|
781
781
|
"kind": "sources",
|
|
782
782
|
"markdown": "- [Instagram API with Instagram Login](https://developers.facebook.com/docs/instagram-platform/instagram-api-with-instagram-login/)\n- [Business Login for Instagram](https://developers.facebook.com/docs/instagram-platform/instagram-api-with-instagram-login/business-login)\n- [Permission descriptions and App Review requirement](https://developers.facebook.com/docs/permissions)\n- [App modes](https://developers.facebook.com/docs/development/build-and-test/app-modes)\n- [Switch to a professional account](https://creatorsupport.creatoriq.com/hc/en-us/articles/13578083261709-How-do-I-switch-from-a-Personal-to-a-Professional-Instagram-account)"
|
|
783
|
-
},
|
|
784
|
-
{
|
|
785
|
-
"id": "investigate-with-this-connection",
|
|
786
|
-
"title": "Investigate with this connection",
|
|
787
|
-
"kind": "detail",
|
|
788
|
-
"markdown": "Your agent can use `list_marketing_queries` and `query_marketing_source` for `posts`, `comments`. Discover the exact parameters and required setup with:\n\n```sh\nsprid marketing-review capabilities --app <slug> --source instagram --json\n```\n\nQueries Sprid’s stored publishes, metric snapshots and inbox for the linked content account. No live platform sync or paid API read. Missing metrics are unmeasured; this does not expose the platform’s entire API. See [connected queries](https://sprid.studio/docs/queries) for the shared workflow. Extra operations may need additional read permissions; a stored key alone is not live verification."
|
|
789
783
|
}
|
|
790
784
|
],
|
|
791
|
-
"markdown": "# Instagram\n\n**What Sprid does with this:** Publish approved posts to Instagram and see how they perform.\n\n## You need\n\
|
|
792
|
-
"revision": "
|
|
785
|
+
"markdown": "# Instagram\n\n**What Sprid does with this:** Publish approved posts to Instagram and see how they perform.\n\n## You need\n\n- An Instagram **Business** or **Creator** account. A Facebook Page is optional. No account yet? Start with [Create your social accounts](https://sprid.studio/docs/connect/social-accounts).\n- Your phone for any two-factor prompt.\n\nTo switch a personal account: profile → **≡ → Settings and activity → For professionals → Account type and tools → Switch to professional account** → pick a category → **Creator** or **Business**. You can skip linking a Facebook Page.\n\n## Then run\n\n```\nsprid connect instagram --account <slug>\n```\n\nReplace `<slug>` with your Sprid account slug, or use **Settings → Channels → Connect Instagram** in Sprid. In an agent-controlled browser, add `--no-browser` and open the returned link in the session for the intended account. Keep that link private.\n\n## Click path (the connect)\n\n1. Sign in to the Instagram account you want. If another account is signed in, sign out first.\n2. Check the handle in the consent dialog and leave the requested permissions enabled.\n3. Click **Allow** to return to Sprid.\n\n## How to check it worked\n\nRun `sprid status` and check that Instagram shows the right handle. Before scheduling a batch, publish one reviewed post and check it on Instagram.\n\n## If it fails\n\n- **Account not eligible:** switch to Business or Creator, then reconnect.\n- **Already connected elsewhere:** check the handle. If the wrong account was signed in, cancel and restart. Move a connection only if you mean to change its Sprid destination.\n- **Connection expired or permissions missing:** run the connect command again and approve all requested access.\n- **App unavailable, “Invalid Scopes” or a redirect error:** send the error to [Sprid support](mailto:hello@sprid.studio). Only Sprid can fix these.\n- **Long-lived token exchange fails after Allow:** authorization did not complete. Send the error text to [Sprid support](mailto:hello@sprid.studio). If Sprid invites your account as a tester, open Instagram **Settings → Website permissions → Apps and websites → Tester Invites**, accept Sprid-IG, then start a fresh connection. The tab may only appear after an invitation. Do not create another Instagram account or your own Meta developer app. `Unsupported request - method type: get` alone does not identify the cause.\n\n## Investigate with this connection\n\nOperations `posts` and `comments`, read from Sprid’s stored publishes, metric snapshots and inbox (no live platform read; missing metrics are unmeasured, not zero).\n\n```sh\nsprid marketing-review capabilities --app <slug> --source instagram --json\n```\n\nSee [connected queries](https://sprid.studio/docs/queries).\n\n## Sources\n\n- [Instagram API with Instagram Login](https://developers.facebook.com/docs/instagram-platform/instagram-api-with-instagram-login/)\n- [Business Login for Instagram](https://developers.facebook.com/docs/instagram-platform/instagram-api-with-instagram-login/business-login)\n- [Permission descriptions and App Review requirement](https://developers.facebook.com/docs/permissions)\n- [App modes](https://developers.facebook.com/docs/development/build-and-test/app-modes)\n- [Switch to a professional account](https://creatorsupport.creatoriq.com/hc/en-us/articles/13578083261709-How-do-I-switch-from-a-Personal-to-a-Professional-Instagram-account)\n",
|
|
786
|
+
"revision": "116e5b47d45175e7"
|
|
793
787
|
},
|
|
794
788
|
{
|
|
795
789
|
"id": "tiktok",
|
|
@@ -802,7 +796,7 @@ export const GUIDES = [
|
|
|
802
796
|
"id": "you-need",
|
|
803
797
|
"title": "You need",
|
|
804
798
|
"kind": "requirements",
|
|
805
|
-
"markdown": "A TikTok account you can sign in to
|
|
799
|
+
"markdown": "A TikTok account you can sign in to, set to public if you want public posts."
|
|
806
800
|
},
|
|
807
801
|
{
|
|
808
802
|
"id": "then-run",
|
|
@@ -814,41 +808,41 @@ export const GUIDES = [
|
|
|
814
808
|
"id": "click-path-the-connect",
|
|
815
809
|
"title": "Click path (the connect)",
|
|
816
810
|
"kind": "steps",
|
|
817
|
-
"markdown": "1. Sign in to TikTok in the browser that opens
|
|
811
|
+
"markdown": "1. Sign in to TikTok in the browser that opens, or scan the QR code with your phone.\n2. Review the requested access and click **Authorize**.\n3. Back in Sprid, check the connected handle."
|
|
818
812
|
},
|
|
819
813
|
{
|
|
820
814
|
"id": "how-to-check-it-worked",
|
|
821
815
|
"title": "How to check it worked",
|
|
822
816
|
"kind": "verify",
|
|
823
|
-
"markdown": "Run `sprid status` and check
|
|
817
|
+
"markdown": "Run `sprid status` and check the handle. To test publishing, post a reviewed post as **Only me** and find it on your profile."
|
|
824
818
|
},
|
|
825
819
|
{
|
|
826
820
|
"id": "before-publishing",
|
|
827
821
|
"title": "Before publishing",
|
|
828
822
|
"kind": "detail",
|
|
829
|
-
"markdown": "
|
|
823
|
+
"markdown": "TikTok requires you to choose these on every post, with nothing pre-filled:\n\n- Audience (privacy) and whether to allow comments. Videos also offer Duet and Stitch where your account allows them.\n- The commercial-content disclosure, if the post promotes your business or another brand. Branded content cannot use **Only me**.\n- The music and branded-content terms shown above the publish button.\n\nIn a batch, your choices apply to every post shown. Rescheduling a booking keeps its original choices."
|
|
830
824
|
},
|
|
831
825
|
{
|
|
832
826
|
"id": "if-it-fails",
|
|
833
827
|
"title": "If it fails",
|
|
834
828
|
"kind": "troubleshooting",
|
|
835
|
-
"markdown": "- **A public post arrives as private:** use **Send as a draft** and finish
|
|
829
|
+
"markdown": "- **A public post arrives as private:** use **Send as a draft** and finish in TikTok, and tell [Sprid support](mailto:hello@sprid.studio) about the public-posting restriction.\n- **Publishing limit reached:** retry later, or send as a draft.\n- **“Checking your TikTok account…” stays on screen:** select **Retry**, then reconnect if it still fails.\n- **Publish stays disabled:** complete the audience and disclosure choices and resolve any message beside the button."
|
|
830
|
+
},
|
|
831
|
+
{
|
|
832
|
+
"id": "investigate-with-this-connection",
|
|
833
|
+
"title": "Investigate with this connection",
|
|
834
|
+
"kind": "detail",
|
|
835
|
+
"markdown": "Operations `posts` and `comments`, read from Sprid’s stored publishes, metric snapshots and inbox (no live platform read; missing metrics are unmeasured, not zero).\n\n```sh\nsprid marketing-review capabilities --app <slug> --source tiktok --json\n```\n\nSee [connected queries](https://sprid.studio/docs/queries)."
|
|
836
836
|
},
|
|
837
837
|
{
|
|
838
838
|
"id": "sources",
|
|
839
839
|
"title": "Sources",
|
|
840
840
|
"kind": "sources",
|
|
841
841
|
"markdown": "- [Content Posting API](https://developers.tiktok.com/doc/content-posting-api-get-started)\n- [Direct Post reference](https://developers.tiktok.com/doc/content-posting-api-reference-direct-post)\n- [Query creator info](https://developers.tiktok.com/doc/content-posting-api-reference-query-creator-info)\n- [Content Sharing Guidelines](https://developers.tiktok.com/doc/content-sharing-guidelines)\n- [Login Kit for web](https://developers.tiktok.com/doc/login-kit-web)"
|
|
842
|
-
},
|
|
843
|
-
{
|
|
844
|
-
"id": "investigate-with-this-connection",
|
|
845
|
-
"title": "Investigate with this connection",
|
|
846
|
-
"kind": "detail",
|
|
847
|
-
"markdown": "Your agent can use `list_marketing_queries` and `query_marketing_source` for `posts`, `comments`. Discover the exact parameters and required setup with:\n\n```sh\nsprid marketing-review capabilities --app <slug> --source tiktok --json\n```\n\nQueries Sprid’s stored publishes, metric snapshots and inbox for the linked content account. No live platform sync or paid API read. Missing metrics are unmeasured; this does not expose the platform’s entire API. See [connected queries](https://sprid.studio/docs/queries) for the shared workflow. Extra operations may need additional read permissions; a stored key alone is not live verification."
|
|
848
842
|
}
|
|
849
843
|
],
|
|
850
|
-
"markdown": "# TikTok\n\n**What Sprid does with this:** Publish approved posts to TikTok, or send drafts to finish in the TikTok app.\n\n## You need\n\nA TikTok account you can sign in to
|
|
851
|
-
"revision": "
|
|
844
|
+
"markdown": "# TikTok\n\n**What Sprid does with this:** Publish approved posts to TikTok, or send drafts to finish in the TikTok app.\n\n## You need\n\nA TikTok account you can sign in to, set to public if you want public posts.\n\n## Then run\n\n```\nsprid connect tiktok --account <slug>\n```\n\nReplace `<slug>` with your Sprid account slug.\n\n## Click path (the connect)\n\n1. Sign in to TikTok in the browser that opens, or scan the QR code with your phone.\n2. Review the requested access and click **Authorize**.\n3. Back in Sprid, check the connected handle.\n\n## How to check it worked\n\nRun `sprid status` and check the handle. To test publishing, post a reviewed post as **Only me** and find it on your profile.\n\n## Before publishing\n\nTikTok requires you to choose these on every post, with nothing pre-filled:\n\n- Audience (privacy) and whether to allow comments. Videos also offer Duet and Stitch where your account allows them.\n- The commercial-content disclosure, if the post promotes your business or another brand. Branded content cannot use **Only me**.\n- The music and branded-content terms shown above the publish button.\n\nIn a batch, your choices apply to every post shown. Rescheduling a booking keeps its original choices.\n\n## If it fails\n\n- **A public post arrives as private:** use **Send as a draft** and finish in TikTok, and tell [Sprid support](mailto:hello@sprid.studio) about the public-posting restriction.\n- **Publishing limit reached:** retry later, or send as a draft.\n- **“Checking your TikTok account…” stays on screen:** select **Retry**, then reconnect if it still fails.\n- **Publish stays disabled:** complete the audience and disclosure choices and resolve any message beside the button.\n\n## Investigate with this connection\n\nOperations `posts` and `comments`, read from Sprid’s stored publishes, metric snapshots and inbox (no live platform read; missing metrics are unmeasured, not zero).\n\n```sh\nsprid marketing-review capabilities --app <slug> --source tiktok --json\n```\n\nSee [connected queries](https://sprid.studio/docs/queries).\n\n## Sources\n\n- [Content Posting API](https://developers.tiktok.com/doc/content-posting-api-get-started)\n- [Direct Post reference](https://developers.tiktok.com/doc/content-posting-api-reference-direct-post)\n- [Query creator info](https://developers.tiktok.com/doc/content-posting-api-reference-query-creator-info)\n- [Content Sharing Guidelines](https://developers.tiktok.com/doc/content-sharing-guidelines)\n- [Login Kit for web](https://developers.tiktok.com/doc/login-kit-web)\n",
|
|
845
|
+
"revision": "710f233b9a644bb3"
|
|
852
846
|
},
|
|
853
847
|
{
|
|
854
848
|
"id": "youtube",
|
|
@@ -861,13 +855,7 @@ export const GUIDES = [
|
|
|
861
855
|
"id": "you-need",
|
|
862
856
|
"title": "You need",
|
|
863
857
|
"kind": "requirements",
|
|
864
|
-
"markdown": "A Google account with a YouTube channel. To create
|
|
865
|
-
},
|
|
866
|
-
{
|
|
867
|
-
"id": "set-up-additional-channels",
|
|
868
|
-
"title": "Set up additional channels",
|
|
869
|
-
"kind": "steps",
|
|
870
|
-
"markdown": "Open [your channel list](https://www.youtube.com/channel_switcher) and verify the Google account that should own the new channels. Reuse existing channels or choose **Create a channel** for a separate brand, creator, topic or audience. See [Create your social accounts](https://sprid.studio/docs/connect/social-accounts).\n\nIf YouTube requires advanced-feature verification, the owner completes the offered video, ID or channel-history route. Submission can remain pending review. Continue other platforms, then recheck eligibility before retrying. This is separate from authorizing Sprid and was observed when creating additional channels in September 2026."
|
|
858
|
+
"markdown": "A Google account with a YouTube channel. To create one: [YouTube](https://youtube.com) → profile picture → **Create a channel**. For extra channels (another brand, creator or audience) and owner verification, see [Create your social accounts](https://sprid.studio/docs/connect/social-accounts)."
|
|
871
859
|
},
|
|
872
860
|
{
|
|
873
861
|
"id": "then-run",
|
|
@@ -879,7 +867,7 @@ export const GUIDES = [
|
|
|
879
867
|
"id": "click-path-the-connect",
|
|
880
868
|
"title": "Click path (the connect)",
|
|
881
869
|
"kind": "steps",
|
|
882
|
-
"markdown": "1. Sign in with your Google account.\n2. Choose the channel
|
|
870
|
+
"markdown": "1. Sign in with your Google account.\n2. Choose the channel to upload to, including a Brand Account channel if you use one.\n3. Review the requested access and click **Continue**."
|
|
883
871
|
},
|
|
884
872
|
{
|
|
885
873
|
"id": "how-to-check-it-worked",
|
|
@@ -891,23 +879,23 @@ export const GUIDES = [
|
|
|
891
879
|
"id": "if-it-fails",
|
|
892
880
|
"title": "If it fails",
|
|
893
881
|
"kind": "troubleshooting",
|
|
894
|
-
"markdown": "- **Google blocks sign-in or says Sprid is unverified:**
|
|
882
|
+
"markdown": "- **Google blocks sign-in or says Sprid is unverified:** send the message to [Sprid support](mailto:hello@sprid.studio).\n- **Upload is private although you chose Public:** check visibility in **YouTube Studio → Content**. If YouTube will not let you change it, contact Sprid support.\n- **Upload limit reached:** wait, and check the post’s status in Sprid before submitting again.\n- **Creating a channel asks for verification:** the primary owner follows YouTube Studio’s instructions (video, ID or channel history). Review can stay pending; reauthorizing Sprid cannot create the channel. Continue other platforms and recheck eligibility later."
|
|
883
|
+
},
|
|
884
|
+
{
|
|
885
|
+
"id": "investigate-with-this-connection",
|
|
886
|
+
"title": "Investigate with this connection",
|
|
887
|
+
"kind": "detail",
|
|
888
|
+
"markdown": "Operations `posts` and `comments`, read from Sprid’s stored publishes, metric snapshots and inbox (no live platform read; missing metrics are unmeasured, not zero).\n\n```sh\nsprid marketing-review capabilities --app <slug> --source youtube --json\n```\n\nSee [connected queries](https://sprid.studio/docs/queries)."
|
|
895
889
|
},
|
|
896
890
|
{
|
|
897
891
|
"id": "sources",
|
|
898
892
|
"title": "Sources",
|
|
899
893
|
"kind": "sources",
|
|
900
894
|
"markdown": "- [Feature eligibility and owner verification](https://support.google.com/youtube/answer/9891124?hl=en)\n- [Getting started](https://developers.google.com/youtube/v3/getting-started)\n- [`videos.insert` reference](https://developers.google.com/youtube/v3/docs/videos/insert)\n- [Quota and compliance audits](https://developers.google.com/youtube/v3/guides/quota_and_compliance_audits)\n- [Revision history](https://developers.google.com/youtube/v3/revision_history)"
|
|
901
|
-
},
|
|
902
|
-
{
|
|
903
|
-
"id": "investigate-with-this-connection",
|
|
904
|
-
"title": "Investigate with this connection",
|
|
905
|
-
"kind": "detail",
|
|
906
|
-
"markdown": "Your agent can use `list_marketing_queries` and `query_marketing_source` for `posts`, `comments`. Discover the exact parameters and required setup with:\n\n```sh\nsprid marketing-review capabilities --app <slug> --source youtube --json\n```\n\nQueries Sprid’s stored publishes, metric snapshots and inbox for the linked content account. No live platform sync or paid API read. Missing metrics are unmeasured; this does not expose the platform’s entire API. See [connected queries](https://sprid.studio/docs/queries) for the shared workflow. Extra operations may need additional read permissions; a stored key alone is not live verification."
|
|
907
895
|
}
|
|
908
896
|
],
|
|
909
|
-
"markdown": "# YouTube\n\n**What Sprid does with this:** Upload approved videos to your YouTube channel and read their results.\n\n## You need\n\nA Google account with a YouTube channel. To create
|
|
910
|
-
"revision": "
|
|
897
|
+
"markdown": "# YouTube\n\n**What Sprid does with this:** Upload approved videos to your YouTube channel and read their results.\n\n## You need\n\nA Google account with a YouTube channel. To create one: [YouTube](https://youtube.com) → profile picture → **Create a channel**. For extra channels (another brand, creator or audience) and owner verification, see [Create your social accounts](https://sprid.studio/docs/connect/social-accounts).\n\n## Then run\n\n```\nsprid connect youtube --account <slug>\n```\n\nReplace `<slug>` with your Sprid account slug.\n\n## Click path (the connect)\n\n1. Sign in with your Google account.\n2. Choose the channel to upload to, including a Brand Account channel if you use one.\n3. Review the requested access and click **Continue**.\n\n## How to check it worked\n\nRun `sprid status` and check the channel name. Upload a reviewed reel as private, then check **YouTube Studio → Content**.\n\n## If it fails\n\n- **Google blocks sign-in or says Sprid is unverified:** send the message to [Sprid support](mailto:hello@sprid.studio).\n- **Upload is private although you chose Public:** check visibility in **YouTube Studio → Content**. If YouTube will not let you change it, contact Sprid support.\n- **Upload limit reached:** wait, and check the post’s status in Sprid before submitting again.\n- **Creating a channel asks for verification:** the primary owner follows YouTube Studio’s instructions (video, ID or channel history). Review can stay pending; reauthorizing Sprid cannot create the channel. Continue other platforms and recheck eligibility later.\n\n## Investigate with this connection\n\nOperations `posts` and `comments`, read from Sprid’s stored publishes, metric snapshots and inbox (no live platform read; missing metrics are unmeasured, not zero).\n\n```sh\nsprid marketing-review capabilities --app <slug> --source youtube --json\n```\n\nSee [connected queries](https://sprid.studio/docs/queries).\n\n## Sources\n\n- [Feature eligibility and owner verification](https://support.google.com/youtube/answer/9891124?hl=en)\n- [Getting started](https://developers.google.com/youtube/v3/getting-started)\n- [`videos.insert` reference](https://developers.google.com/youtube/v3/docs/videos/insert)\n- [Quota and compliance audits](https://developers.google.com/youtube/v3/guides/quota_and_compliance_audits)\n- [Revision history](https://developers.google.com/youtube/v3/revision_history)\n",
|
|
898
|
+
"revision": "5c7cb25150e1d261"
|
|
911
899
|
},
|
|
912
900
|
{
|
|
913
901
|
"id": "linkedin",
|
|
@@ -920,7 +908,7 @@ export const GUIDES = [
|
|
|
920
908
|
"id": "you-need",
|
|
921
909
|
"title": "You need",
|
|
922
910
|
"kind": "requirements",
|
|
923
|
-
"markdown": "A LinkedIn account.
|
|
911
|
+
"markdown": "A LinkedIn account. Publishing to a Company Page needs **Super admin** or **Content admin** access on the Page."
|
|
924
912
|
},
|
|
925
913
|
{
|
|
926
914
|
"id": "then-run",
|
|
@@ -932,35 +920,35 @@ export const GUIDES = [
|
|
|
932
920
|
"id": "click-path-the-connect",
|
|
933
921
|
"title": "Click path (the connect)",
|
|
934
922
|
"kind": "steps",
|
|
935
|
-
"markdown": "1. Sign in to LinkedIn in the browser that opens.\n2. Review the access
|
|
923
|
+
"markdown": "1. Sign in to LinkedIn in the browser that opens.\n2. Review the requested access and click **Allow**.\n3. Back in Sprid, check the connected name."
|
|
936
924
|
},
|
|
937
925
|
{
|
|
938
926
|
"id": "how-to-check-it-worked",
|
|
939
927
|
"title": "How to check it worked",
|
|
940
928
|
"kind": "verify",
|
|
941
|
-
"markdown": "Run `sprid status` and confirm the destination. After publishing a reviewed carousel,
|
|
929
|
+
"markdown": "Run `sprid status` and confirm the destination. After publishing a reviewed carousel, check the document post on LinkedIn."
|
|
942
930
|
},
|
|
943
931
|
{
|
|
944
932
|
"id": "if-it-fails",
|
|
945
933
|
"title": "If it fails",
|
|
946
934
|
"kind": "troubleshooting",
|
|
947
|
-
"markdown": "- **Company Page missing:** ask its Super admin to check your role under **Page → Settings → Manage admins**.
|
|
935
|
+
"markdown": "- **Company Page missing:** ask its Super admin to check your role under **Page → Settings → Manage admins**. If Page publishing is unavailable, contact [Sprid support](mailto:hello@sprid.studio).\n- **Access denied:** reconnect and check you can still publish to the destination.\n- **Connection expiring or expired:** run the connect command again."
|
|
936
|
+
},
|
|
937
|
+
{
|
|
938
|
+
"id": "investigate-with-this-connection",
|
|
939
|
+
"title": "Investigate with this connection",
|
|
940
|
+
"kind": "detail",
|
|
941
|
+
"markdown": "Operations `posts` and `comments`, read from Sprid’s stored publishes, metric snapshots and inbox (no live platform read; missing metrics are unmeasured, not zero).\n\n```sh\nsprid marketing-review capabilities --app <slug> --source linkedin --json\n```\n\nSee [connected queries](https://sprid.studio/docs/queries)."
|
|
948
942
|
},
|
|
949
943
|
{
|
|
950
944
|
"id": "sources",
|
|
951
945
|
"title": "Sources",
|
|
952
946
|
"kind": "sources",
|
|
953
947
|
"markdown": "- [Share on LinkedIn](https://learn.microsoft.com/en-us/linkedin/consumer/integrations/self-serve/share-on-linkedin)\n- [Posts API permissions](https://learn.microsoft.com/en-us/linkedin/marketing/community-management/shares/posts-api)\n- [Documents API](https://learn.microsoft.com/en-us/linkedin/marketing/community-management/shares/documents-api)"
|
|
954
|
-
},
|
|
955
|
-
{
|
|
956
|
-
"id": "investigate-with-this-connection",
|
|
957
|
-
"title": "Investigate with this connection",
|
|
958
|
-
"kind": "detail",
|
|
959
|
-
"markdown": "Your agent can use `list_marketing_queries` and `query_marketing_source` for `posts`, `comments`. Discover the exact parameters and required setup with:\n\n```sh\nsprid marketing-review capabilities --app <slug> --source linkedin --json\n```\n\nQueries Sprid’s stored publishes, metric snapshots and inbox for the linked content account. No live platform sync or paid API read. Missing metrics are unmeasured; this does not expose the platform’s entire API. See [connected queries](https://sprid.studio/docs/queries) for the shared workflow. Extra operations may need additional read permissions; a stored key alone is not live verification."
|
|
960
948
|
}
|
|
961
949
|
],
|
|
962
|
-
"markdown": "# LinkedIn\n\n**What Sprid does with this:** Publish approved carousels to LinkedIn as swipeable document posts.\n\n## You need\n\nA LinkedIn account.
|
|
963
|
-
"revision": "
|
|
950
|
+
"markdown": "# LinkedIn\n\n**What Sprid does with this:** Publish approved carousels to LinkedIn as swipeable document posts.\n\n## You need\n\nA LinkedIn account. Publishing to a Company Page needs **Super admin** or **Content admin** access on the Page.\n\n## Then run\n\n```\nsprid connect linkedin --account <slug>\n```\n\nReplace `<slug>` with your Sprid account slug.\n\n## Click path (the connect)\n\n1. Sign in to LinkedIn in the browser that opens.\n2. Review the requested access and click **Allow**.\n3. Back in Sprid, check the connected name.\n\n## How to check it worked\n\nRun `sprid status` and confirm the destination. After publishing a reviewed carousel, check the document post on LinkedIn.\n\n## If it fails\n\n- **Company Page missing:** ask its Super admin to check your role under **Page → Settings → Manage admins**. If Page publishing is unavailable, contact [Sprid support](mailto:hello@sprid.studio).\n- **Access denied:** reconnect and check you can still publish to the destination.\n- **Connection expiring or expired:** run the connect command again.\n\n## Investigate with this connection\n\nOperations `posts` and `comments`, read from Sprid’s stored publishes, metric snapshots and inbox (no live platform read; missing metrics are unmeasured, not zero).\n\n```sh\nsprid marketing-review capabilities --app <slug> --source linkedin --json\n```\n\nSee [connected queries](https://sprid.studio/docs/queries).\n\n## Sources\n\n- [Share on LinkedIn](https://learn.microsoft.com/en-us/linkedin/consumer/integrations/self-serve/share-on-linkedin)\n- [Posts API permissions](https://learn.microsoft.com/en-us/linkedin/marketing/community-management/shares/posts-api)\n- [Documents API](https://learn.microsoft.com/en-us/linkedin/marketing/community-management/shares/documents-api)\n",
|
|
951
|
+
"revision": "40239bfd7b93d752"
|
|
964
952
|
},
|
|
965
953
|
{
|
|
966
954
|
"id": "facebook",
|
|
@@ -973,7 +961,7 @@ export const GUIDES = [
|
|
|
973
961
|
"id": "you-need",
|
|
974
962
|
"title": "You need",
|
|
975
963
|
"kind": "requirements",
|
|
976
|
-
"markdown": "A Facebook **Page** you can publish to
|
|
964
|
+
"markdown": "A Facebook **Page** you can publish to: **Professional dashboard → Page access** should show **Facebook access**, or **task access** that includes **Content**. Personal profiles cannot be connected, and Instagram does not need to be linked. To create a Page or add it to a business portfolio, see [Create your social accounts](https://sprid.studio/docs/connect/social-accounts)."
|
|
977
965
|
},
|
|
978
966
|
{
|
|
979
967
|
"id": "then-run",
|
|
@@ -985,35 +973,35 @@ export const GUIDES = [
|
|
|
985
973
|
"id": "click-path-the-connect",
|
|
986
974
|
"title": "Click path (the connect)",
|
|
987
975
|
"kind": "steps",
|
|
988
|
-
"markdown": "1. Sign in
|
|
976
|
+
"markdown": "1. Sign in with the Facebook profile that manages the Page.\n2. Select the Page and leave the requested permissions enabled.\n3. Click **Continue / Done** to return to Sprid.\n4. If Sprid lists several Pages, rerun with `--page <id>` using the id in the message. The profile’s name is not the Page destination."
|
|
989
977
|
},
|
|
990
978
|
{
|
|
991
979
|
"id": "how-to-check-it-worked",
|
|
992
980
|
"title": "How to check it worked",
|
|
993
981
|
"kind": "verify",
|
|
994
|
-
"markdown": "Run `sprid status` and check the
|
|
982
|
+
"markdown": "Run `sprid status` and check the Page name. After publishing a reviewed post, check it on that Page."
|
|
995
983
|
},
|
|
996
984
|
{
|
|
997
985
|
"id": "if-it-fails",
|
|
998
986
|
"title": "If it fails",
|
|
999
987
|
"kind": "troubleshooting",
|
|
1000
|
-
"markdown": "- **No Pages found:** check your Page access, reconnect and select the Page in Facebook’s chooser.\n- **Permission missing:** reconnect and approve all requested permissions.\n- **Page already connected:** check
|
|
988
|
+
"markdown": "- **No Pages found:** check your Page access, reconnect and select the Page in Facebook’s chooser.\n- **Permission missing:** reconnect and approve all requested permissions.\n- **Page already connected:** check you picked the intended Page. A Page connects to one Sprid account; disconnect the old one only if you mean to move it.\n- **“Invalid Scopes”, app unavailable or “URL blocked”:** contact [Sprid support](mailto:hello@sprid.studio). Only Sprid can fix these."
|
|
989
|
+
},
|
|
990
|
+
{
|
|
991
|
+
"id": "investigate-with-this-connection",
|
|
992
|
+
"title": "Investigate with this connection",
|
|
993
|
+
"kind": "detail",
|
|
994
|
+
"markdown": "Operations `posts` and `comments`, read from Sprid’s stored publishes, metric snapshots and inbox (no live platform read; missing metrics are unmeasured, not zero).\n\n```sh\nsprid marketing-review capabilities --app <slug> --source facebook --json\n```\n\nSee [connected queries](https://sprid.studio/docs/queries)."
|
|
1001
995
|
},
|
|
1002
996
|
{
|
|
1003
997
|
"id": "sources",
|
|
1004
998
|
"title": "Sources",
|
|
1005
999
|
"kind": "sources",
|
|
1006
1000
|
"markdown": "- [Pages API getting started](https://developers.facebook.com/docs/pages-api/getting-started)\n- [Permission descriptions and review requirements](https://developers.facebook.com/docs/permissions)\n- [App modes](https://developers.facebook.com/docs/development/build-and-test/app-modes)\n- [Facebook access vs task access on the new Pages experience](https://www.facebook.com/business/help/582754542592549)"
|
|
1007
|
-
},
|
|
1008
|
-
{
|
|
1009
|
-
"id": "investigate-with-this-connection",
|
|
1010
|
-
"title": "Investigate with this connection",
|
|
1011
|
-
"kind": "detail",
|
|
1012
|
-
"markdown": "Your agent can use `list_marketing_queries` and `query_marketing_source` for `posts`, `comments`. Discover the exact parameters and required setup with:\n\n```sh\nsprid marketing-review capabilities --app <slug> --source facebook --json\n```\n\nQueries Sprid’s stored publishes, metric snapshots and inbox for the linked content account. No live platform sync or paid API read. Missing metrics are unmeasured; this does not expose the platform’s entire API. See [connected queries](https://sprid.studio/docs/queries) for the shared workflow. Extra operations may need additional read permissions; a stored key alone is not live verification."
|
|
1013
1001
|
}
|
|
1014
1002
|
],
|
|
1015
|
-
"markdown": "# Facebook Page\n\n**What Sprid does with this:** Publish approved posts to your Facebook Page and see their results.\n\n## You need\n\nA Facebook **Page** you can publish to
|
|
1016
|
-
"revision": "
|
|
1003
|
+
"markdown": "# Facebook Page\n\n**What Sprid does with this:** Publish approved posts to your Facebook Page and see their results.\n\n## You need\n\nA Facebook **Page** you can publish to: **Professional dashboard → Page access** should show **Facebook access**, or **task access** that includes **Content**. Personal profiles cannot be connected, and Instagram does not need to be linked. To create a Page or add it to a business portfolio, see [Create your social accounts](https://sprid.studio/docs/connect/social-accounts).\n\n## Then run\n\n```\nsprid connect facebook --account <slug>\n```\n\nReplace `<slug>` with your Sprid account slug.\n\n## Click path (the connect)\n\n1. Sign in with the Facebook profile that manages the Page.\n2. Select the Page and leave the requested permissions enabled.\n3. Click **Continue / Done** to return to Sprid.\n4. If Sprid lists several Pages, rerun with `--page <id>` using the id in the message. The profile’s name is not the Page destination.\n\n## How to check it worked\n\nRun `sprid status` and check the Page name. After publishing a reviewed post, check it on that Page.\n\n## If it fails\n\n- **No Pages found:** check your Page access, reconnect and select the Page in Facebook’s chooser.\n- **Permission missing:** reconnect and approve all requested permissions.\n- **Page already connected:** check you picked the intended Page. A Page connects to one Sprid account; disconnect the old one only if you mean to move it.\n- **“Invalid Scopes”, app unavailable or “URL blocked”:** contact [Sprid support](mailto:hello@sprid.studio). Only Sprid can fix these.\n\n## Investigate with this connection\n\nOperations `posts` and `comments`, read from Sprid’s stored publishes, metric snapshots and inbox (no live platform read; missing metrics are unmeasured, not zero).\n\n```sh\nsprid marketing-review capabilities --app <slug> --source facebook --json\n```\n\nSee [connected queries](https://sprid.studio/docs/queries).\n\n## Sources\n\n- [Pages API getting started](https://developers.facebook.com/docs/pages-api/getting-started)\n- [Permission descriptions and review requirements](https://developers.facebook.com/docs/permissions)\n- [App modes](https://developers.facebook.com/docs/development/build-and-test/app-modes)\n- [Facebook access vs task access on the new Pages experience](https://www.facebook.com/business/help/582754542592549)\n",
|
|
1004
|
+
"revision": "414500d53feab293"
|
|
1017
1005
|
},
|
|
1018
1006
|
{
|
|
1019
1007
|
"id": "x",
|
|
@@ -1038,7 +1026,7 @@ export const GUIDES = [
|
|
|
1038
1026
|
"id": "click-path-the-connect",
|
|
1039
1027
|
"title": "Click path (the connect)",
|
|
1040
1028
|
"kind": "steps",
|
|
1041
|
-
"markdown": "1. Sign in to the X account you want to use.\n2. Review
|
|
1029
|
+
"markdown": "1. Sign in to the X account you want to use.\n2. Review the requested access and click **Authorize app**.\n3. Back in Sprid, check the connected handle."
|
|
1042
1030
|
},
|
|
1043
1031
|
{
|
|
1044
1032
|
"id": "how-to-check-it-worked",
|
|
@@ -1050,29 +1038,29 @@ export const GUIDES = [
|
|
|
1050
1038
|
"id": "the-caption-is-its-own-field",
|
|
1051
1039
|
"title": "The caption is its own field",
|
|
1052
1040
|
"kind": "detail",
|
|
1053
|
-
"markdown": "
|
|
1041
|
+
"markdown": "The **X caption** has a **280-character** limit. Left empty, it uses your shared caption, which must then fit too. Carousels over four images publish as a thread, with the caption on the first post."
|
|
1054
1042
|
},
|
|
1055
1043
|
{
|
|
1056
1044
|
"id": "if-it-fails",
|
|
1057
1045
|
"title": "If it fails",
|
|
1058
1046
|
"kind": "troubleshooting",
|
|
1059
|
-
"markdown": "- **Connection expired or refresh failed:** run the connect command again.\n- **Access denied after reconnecting:**
|
|
1047
|
+
"markdown": "- **Connection expired or refresh failed:** run the connect command again.\n- **Access denied after reconnecting:** send the error to [Sprid support](mailto:hello@sprid.studio).\n- **Publishing limit reached:** check the post’s status and retry when the limit resets."
|
|
1048
|
+
},
|
|
1049
|
+
{
|
|
1050
|
+
"id": "investigate-with-this-connection",
|
|
1051
|
+
"title": "Investigate with this connection",
|
|
1052
|
+
"kind": "detail",
|
|
1053
|
+
"markdown": "Operations `posts` and `comments`, read from Sprid’s stored publishes, metric snapshots and inbox (no live platform read; missing metrics are unmeasured, not zero).\n\n```sh\nsprid marketing-review capabilities --app <slug> --source x --json\n```\n\nSee [connected queries](https://sprid.studio/docs/queries)."
|
|
1060
1054
|
},
|
|
1061
1055
|
{
|
|
1062
1056
|
"id": "sources",
|
|
1063
1057
|
"title": "Sources",
|
|
1064
1058
|
"kind": "sources",
|
|
1065
1059
|
"markdown": "- [OAuth 2.0 authorization code with PKCE](https://docs.x.com/resources/fundamentals/authentication/oauth-2-0/authorization-code)\n- [Create a Post](https://docs.x.com/x-api/posts/create-post)\n- [Chunked media upload](https://docs.x.com/x-api/media/quickstart/media-upload-chunked)"
|
|
1066
|
-
},
|
|
1067
|
-
{
|
|
1068
|
-
"id": "investigate-with-this-connection",
|
|
1069
|
-
"title": "Investigate with this connection",
|
|
1070
|
-
"kind": "detail",
|
|
1071
|
-
"markdown": "Your agent can use `list_marketing_queries` and `query_marketing_source` for `posts`, `comments`. Discover the exact parameters and required setup with:\n\n```sh\nsprid marketing-review capabilities --app <slug> --source x --json\n```\n\nQueries Sprid’s stored publishes, metric snapshots and inbox for the linked content account. No live platform sync or paid API read. Missing metrics are unmeasured; this does not expose the platform’s entire API. See [connected queries](https://sprid.studio/docs/queries) for the shared workflow. Extra operations may need additional read permissions; a stored key alone is not live verification."
|
|
1072
1060
|
}
|
|
1073
1061
|
],
|
|
1074
|
-
"markdown": "# X\n\n**What Sprid does with this:** Publish approved posts to X and see how they perform.\n\n## You need\n\nAn X account you can sign in to. Sprid handles the developer connection.\n\n## Then run\n\n```\nsprid connect x --account <slug>\n```\n\nReplace `<slug>` with your Sprid account slug.\n\n## Click path (the connect)\n\n1. Sign in to the X account you want to use.\n2. Review
|
|
1075
|
-
"revision": "
|
|
1062
|
+
"markdown": "# X\n\n**What Sprid does with this:** Publish approved posts to X and see how they perform.\n\n## You need\n\nAn X account you can sign in to. Sprid handles the developer connection.\n\n## Then run\n\n```\nsprid connect x --account <slug>\n```\n\nReplace `<slug>` with your Sprid account slug.\n\n## Click path (the connect)\n\n1. Sign in to the X account you want to use.\n2. Review the requested access and click **Authorize app**.\n3. Back in Sprid, check the connected handle.\n\n## How to check it worked\n\nRun `sprid status` and confirm the handle. After publishing a reviewed post, check it on X.\n\n## The caption is its own field\n\nThe **X caption** has a **280-character** limit. Left empty, it uses your shared caption, which must then fit too. Carousels over four images publish as a thread, with the caption on the first post.\n\n## If it fails\n\n- **Connection expired or refresh failed:** run the connect command again.\n- **Access denied after reconnecting:** send the error to [Sprid support](mailto:hello@sprid.studio).\n- **Publishing limit reached:** check the post’s status and retry when the limit resets.\n\n## Investigate with this connection\n\nOperations `posts` and `comments`, read from Sprid’s stored publishes, metric snapshots and inbox (no live platform read; missing metrics are unmeasured, not zero).\n\n```sh\nsprid marketing-review capabilities --app <slug> --source x --json\n```\n\nSee [connected queries](https://sprid.studio/docs/queries).\n\n## Sources\n\n- [OAuth 2.0 authorization code with PKCE](https://docs.x.com/resources/fundamentals/authentication/oauth-2-0/authorization-code)\n- [Create a Post](https://docs.x.com/x-api/posts/create-post)\n- [Chunked media upload](https://docs.x.com/x-api/media/quickstart/media-upload-chunked)\n",
|
|
1063
|
+
"revision": "3f5be01bb8544888"
|
|
1076
1064
|
},
|
|
1077
1065
|
{
|
|
1078
1066
|
"id": "pinterest",
|
|
@@ -1085,43 +1073,43 @@ export const GUIDES = [
|
|
|
1085
1073
|
"id": "you-need",
|
|
1086
1074
|
"title": "You need",
|
|
1087
1075
|
"kind": "requirements",
|
|
1088
|
-
"markdown": "- A Pinterest account
|
|
1076
|
+
"markdown": "- A Pinterest account. A free business account is recommended, because Pinterest Analytics requires one.\n- Access to the Sprid account that will own this channel.\n- A board topic in mind. Sprid can create the board during publishing.\n\nYou do **not** create a Pinterest developer app, request API access or copy a token. You only authorize your own Pinterest account."
|
|
1089
1077
|
},
|
|
1090
1078
|
{
|
|
1091
1079
|
"id": "then-run",
|
|
1092
1080
|
"title": "Then run",
|
|
1093
1081
|
"kind": "command",
|
|
1094
|
-
"markdown": "```sh\nsprid connect pinterest --account <slug>\n```\n\nReplace `<slug>` with your Sprid account slug."
|
|
1082
|
+
"markdown": "```sh\nsprid connect pinterest --account <slug>\n```\n\nReplace `<slug>` with your Sprid account slug, or use **Settings → Accounts → [account] → Pinterest → Continue with Pinterest** in Sprid."
|
|
1095
1083
|
},
|
|
1096
1084
|
{
|
|
1097
1085
|
"id": "click-path-the-connect",
|
|
1098
1086
|
"title": "Click path (the connect)",
|
|
1099
1087
|
"kind": "steps",
|
|
1100
|
-
"markdown": "1.
|
|
1088
|
+
"markdown": "1. Check the Pinterest identity in the browser that opens. Sign out first if it is the wrong account.\n2. Review the requested access and authorize Sprid.\n3. Back in Sprid, confirm the connected Pinterest name.\n4. Open a post, select **Publish → Pinterest** and pick the destination in the **Board** picker. If none fits, select **Create board**, name it and choose public or secret; Sprid selects it automatically.\n\nEach Sprid account needs its own connect, even when several Pinterest accounts are signed in to the same browser. Check the identity every time."
|
|
1101
1089
|
},
|
|
1102
1090
|
{
|
|
1103
1091
|
"id": "check-the-connection",
|
|
1104
1092
|
"title": "Check the connection",
|
|
1105
1093
|
"kind": "verify",
|
|
1106
|
-
"markdown": "Run `sprid status` and confirm
|
|
1094
|
+
"markdown": "Run `sprid status` and confirm Pinterest shows the intended account. Open a draft Pin, select **Publish → Pinterest** and confirm the intended board appears before approving any schedule.\n\nAfter the first Pin publishes, open Pinterest signed out or from another account and check the Pin, board, visual, title and destination. A successful API response does not prove public visibility."
|
|
1107
1095
|
},
|
|
1108
1096
|
{
|
|
1109
1097
|
"id": "trial-and-standard-access",
|
|
1110
1098
|
"title": "Trial and Standard access",
|
|
1111
1099
|
"kind": "detail",
|
|
1112
|
-
"markdown": "
|
|
1100
|
+
"markdown": "Publishing and scheduling need **Sprid’s** Pinterest app to have Standard access. With Trial access you can connect and browse boards, but Sprid refuses to publish or schedule. This is Sprid’s approval, not something you apply for, and reconnecting does not change it. Keep preparing drafts, but do not treat them as booked."
|
|
1113
1101
|
},
|
|
1114
1102
|
{
|
|
1115
1103
|
"id": "prepare-the-account",
|
|
1116
1104
|
"title": "Prepare the account",
|
|
1117
1105
|
"kind": "detail",
|
|
1118
|
-
"markdown": "
|
|
1106
|
+
"markdown": "Create a few specific boards around topics people search for, such as “Small apartment viewing checklist” rather than “Inspiration”. Board names, descriptions and saved Pins give Pinterest context.\n\nClaim your website in Pinterest where possible: it links Pins from that site to the profile and expands website analytics. A website can be claimed by only one Pinterest account, so decide which market or brand owns it before connecting several.\n\nRead [Pinterest content and publishing](https://sprid.studio/docs/pinterest) before preparing the first batch."
|
|
1119
1107
|
},
|
|
1120
1108
|
{
|
|
1121
1109
|
"id": "if-it-fails",
|
|
1122
1110
|
"title": "If it fails",
|
|
1123
1111
|
"kind": "troubleshooting",
|
|
1124
|
-
"markdown": "- **“Pinterest is unavailable until API credentials and an access tier are configured”:** this Sprid deployment is not ready for Pinterest.
|
|
1112
|
+
"markdown": "- **“Pinterest is unavailable until API credentials and an access tier are configured”:** this Sprid deployment is not ready for Pinterest. Follow Sprid’s status or contact support; you do not supply credentials.\n- **Wrong account connected:** disconnect it in Sprid, sign out of Pinterest in that browser, then reconnect and check the identity before authorizing.\n- **“No Pinterest boards yet”:** create one from the board picker. If Sprid asks for board permission, reconnect once; older connections lack the board write scope.\n- **Existing boards missing:** reconnect once, then contact [Sprid support](mailto:hello@sprid.studio) with the account name and error.\n- **Access denied:** confirm the Pinterest account is active and you finished the consent screen. Retry once, then contact Sprid support.\n- **Publishing or scheduling requires Standard access:** see Trial and Standard access above. Boards stay selectable; only Sprid can change the tier.\n- **Analytics unavailable:** use a business account and check the Pin is public. Unavailable data is unavailable, not zero."
|
|
1125
1113
|
},
|
|
1126
1114
|
{
|
|
1127
1115
|
"id": "sources",
|
|
@@ -1130,49 +1118,49 @@ export const GUIDES = [
|
|
|
1130
1118
|
"markdown": "- [Pinterest developer access tiers](https://developer.pinterest.com/docs/key-concepts/access-tiers/)\n- [Pinterest developer guidelines](https://policy.pinterest.com/en/developer-guidelines)\n- [Claim your website](https://help.pinterest.com/en/business/article/claim-your-website)\n- [Pinterest Analytics](https://help.pinterest.com/en/business/article/pinterest-analytics)"
|
|
1131
1119
|
}
|
|
1132
1120
|
],
|
|
1133
|
-
"markdown": "# Pinterest\n\n**What Sprid does with this:** Publish the Pins you select to the right boards, keep their destination links intact and read their results when analytics access is available.\n\n## You need\n\n- A Pinterest account
|
|
1134
|
-
"revision": "
|
|
1121
|
+
"markdown": "# Pinterest\n\n**What Sprid does with this:** Publish the Pins you select to the right boards, keep their destination links intact and read their results when analytics access is available.\n\n## You need\n\n- A Pinterest account. A free business account is recommended, because Pinterest Analytics requires one.\n- Access to the Sprid account that will own this channel.\n- A board topic in mind. Sprid can create the board during publishing.\n\nYou do **not** create a Pinterest developer app, request API access or copy a token. You only authorize your own Pinterest account.\n\n## Then run\n\n```sh\nsprid connect pinterest --account <slug>\n```\n\nReplace `<slug>` with your Sprid account slug, or use **Settings → Accounts → [account] → Pinterest → Continue with Pinterest** in Sprid.\n\n## Click path (the connect)\n\n1. Check the Pinterest identity in the browser that opens. Sign out first if it is the wrong account.\n2. Review the requested access and authorize Sprid.\n3. Back in Sprid, confirm the connected Pinterest name.\n4. Open a post, select **Publish → Pinterest** and pick the destination in the **Board** picker. If none fits, select **Create board**, name it and choose public or secret; Sprid selects it automatically.\n\nEach Sprid account needs its own connect, even when several Pinterest accounts are signed in to the same browser. Check the identity every time.\n\n## Check the connection\n\nRun `sprid status` and confirm Pinterest shows the intended account. Open a draft Pin, select **Publish → Pinterest** and confirm the intended board appears before approving any schedule.\n\nAfter the first Pin publishes, open Pinterest signed out or from another account and check the Pin, board, visual, title and destination. A successful API response does not prove public visibility.\n\n## Trial and Standard access\n\nPublishing and scheduling need **Sprid’s** Pinterest app to have Standard access. With Trial access you can connect and browse boards, but Sprid refuses to publish or schedule. This is Sprid’s approval, not something you apply for, and reconnecting does not change it. Keep preparing drafts, but do not treat them as booked.\n\n## Prepare the account\n\nCreate a few specific boards around topics people search for, such as “Small apartment viewing checklist” rather than “Inspiration”. Board names, descriptions and saved Pins give Pinterest context.\n\nClaim your website in Pinterest where possible: it links Pins from that site to the profile and expands website analytics. A website can be claimed by only one Pinterest account, so decide which market or brand owns it before connecting several.\n\nRead [Pinterest content and publishing](https://sprid.studio/docs/pinterest) before preparing the first batch.\n\n## If it fails\n\n- **“Pinterest is unavailable until API credentials and an access tier are configured”:** this Sprid deployment is not ready for Pinterest. Follow Sprid’s status or contact support; you do not supply credentials.\n- **Wrong account connected:** disconnect it in Sprid, sign out of Pinterest in that browser, then reconnect and check the identity before authorizing.\n- **“No Pinterest boards yet”:** create one from the board picker. If Sprid asks for board permission, reconnect once; older connections lack the board write scope.\n- **Existing boards missing:** reconnect once, then contact [Sprid support](mailto:hello@sprid.studio) with the account name and error.\n- **Access denied:** confirm the Pinterest account is active and you finished the consent screen. Retry once, then contact Sprid support.\n- **Publishing or scheduling requires Standard access:** see Trial and Standard access above. Boards stay selectable; only Sprid can change the tier.\n- **Analytics unavailable:** use a business account and check the Pin is public. Unavailable data is unavailable, not zero.\n\n## Sources\n\n- [Pinterest developer access tiers](https://developer.pinterest.com/docs/key-concepts/access-tiers/)\n- [Pinterest developer guidelines](https://policy.pinterest.com/en/developer-guidelines)\n- [Claim your website](https://help.pinterest.com/en/business/article/claim-your-website)\n- [Pinterest Analytics](https://help.pinterest.com/en/business/article/pinterest-analytics)\n",
|
|
1122
|
+
"revision": "a81732fc9409f861"
|
|
1135
1123
|
}
|
|
1136
1124
|
];
|
|
1137
1125
|
export const CONTENT_GUIDES = [
|
|
1138
1126
|
{
|
|
1139
1127
|
"id": "chat",
|
|
1140
1128
|
"title": "Use Sprid in chat",
|
|
1141
|
-
"summary": "Take an app from setup to a reviewed post and confirmed delivery using
|
|
1129
|
+
"summary": "Take an app from setup to a reviewed post and confirmed delivery using only your chat app and a browser. No CLI or installed skills needed.",
|
|
1142
1130
|
"url": "https://sprid.studio/docs/chat",
|
|
1143
|
-
"markdown": "# Use Sprid in chat\n\n**What this guide does:** Take an app from setup to a reviewed post and confirmed delivery using
|
|
1144
|
-
"revision": "
|
|
1131
|
+
"markdown": "# Use Sprid in chat\n\n**What this guide does:** Take an app from setup to a reviewed post and confirmed delivery using only your chat app and a browser. No CLI or installed skills needed.\n\nYou tell the agent what you want; it handles the tool calls below. The tool names are here so the agent knows the order. Setup should only ask for the connection the current task needs.\n\n## Connect Sprid\n\nChoose your chat at `https://sprid.studio/start#chat` and follow its steps. Your chat may call this an app, connector or integration. The address is `https://api.sprid.studio/api/mcp?surface=core`. Sign in to Sprid and authorize the right workspace.\n\nAgent: when available, start with `get_marketing_plan` and reuse its prepared work and next step rather than starting over. Discovery can start from a website or store URL, with no social account.\n\n## Pick the app and account\n\nAgent: call `get_capabilities`, then `list_apps` and `list_accounts`, and reuse what exists. If the app is missing, get its description or website/store URL, confirm it and create it with `upsert_app_profile`. A content account owns voice and media; a channel is one exact social destination. Never pick a handle just because it is first in a list. A missing account is created in the dashboard.\n\n## Connect a destination or data source\n\n- **Social channel:** `get_documentation` with the platform name, then `connect_channel`. The person opens the returned link and approves in the browser; `channel_status` confirms the saved result.\n- **Store or analytics:** the person enters identifiers and the key in the secure form at `https://app.sprid.studio/settings/app-profiles`. Credentials never go in chat, tool arguments or reports. A saved-key indicator only proves configuration; `get_marketing_review` does a live read.\n\n## Bring images or a finished video\n\nDraft copy in the chat, in the account’s voice. No extra model key needed.\n\nIf the chat exposes the attached files, pass them to `import_assets`: each file has `download_url` and `file_id`, optionally `mime_type` and `file_name`. Public HTTPS URLs and existing `{kind, id}` library references also work. Limits: PNG, JPEG, WebP or finished MP4, up to 32 MiB each. Each position reports on its own; retry the missing ones before building the post. Files are copied to the account and deduplicated by bytes; temporary download URLs are not kept.\n\nA `sandbox:` URL or local path can’t be fetched. For an image the chat generated, use the existing file if the host exposes it (not verified for every host); otherwise download it and use the browser upload. Never ask the agent to recreate an image or transcribe binary data.\n\n**Fallback: browser upload.** Call `create_upload_session` with the account and a new UUID `requestId`. The person opens the link and picks the files. Then read `get_studio_job` with the returned ID; its result keys are zero-based positions. The same session and asset IDs work from any other chat. No image-generation charge.\n\n## Create and review the post\n\nCall `create_post_from_assets` with a new UUID `requestId`, the account, ordered `{kind, id}` assets, captions and aspect ratio. Reuse the same ID and inputs if a response is lost.\n\n- `presentation: \"finished\"` keeps artwork as-is: no text overlay, no added music. Images fit inside the canvas, which can add margins.\n- `presentation: \"editable\"` allows `text` and `subtitle` on image slides.\n- One finished video becomes one reel. Never mix a video with image slides.\n\nEdit with `update_post` (captions) and `update_slide` or `batch_update_slides` (slides). Call `preview_post` and check every slide or the video: captions, order, crop, legibility. Preview links work even if the chat can’t embed them. A preview is not approval to publish.\n\n## Make a reel from photos or text\n\nCheck `get_capabilities` for hosted creation first. `create_reel` takes ordered scenes (`imageId`, `text`, `durationMs`), up to 120 seconds, and makes a silent MP4. It costs 3 cents per started render minute, or uses the plan allowance: check `spend_status`, tell the person, and get their go-ahead before sending `confirmed: true`. Save the job ID and read `get_studio_job`. Retrying with the same ID never starts a second render; a stopped job reports `needs_attention` instead of charging again.\n\nApp captures, simulator recordings and your own build scripts run outside remote MCP. Upload their finished files.\n\n## Approve and confirm delivery\n\nThe person opens the returned `/p/<postId>` link, reviews the real media and captions, and picks the channels, time and platform options. TikTok privacy and interaction choices have no defaults and are made on that screen. An agent-supplied confirmation flag is not a human click.\n\nAfter approval, read `get_publication_status`. Keep draft, scheduled, failed and delivered apart, and report delivery only with the platform receipt. Read a failure before retrying. Never repeat a publish call just because a response was lost.\n\nFor results, read `get_documentation` for `marketing-review`. Keep the same app, account and post IDs across clients. `next_actions` gives the next step; an empty `verb` means follow its browser link.\n\n## Limits and troubleshooting\n\n- **Attachment can’t be read:** use the browser upload, not the CLI.\n- **Missing account or service:** set it up in the dashboard. Never paste credentials into chat.\n- **Hosted creation:** check `get_capabilities` before promising it. Store screenshots and store releases are local unless it reports otherwise.\n- **File transfer:** whether a host exposes uploaded or generated files has to be checked per host. A supported schema doesn’t prove it.\n",
|
|
1132
|
+
"revision": "ed4c47ca50f04d9d"
|
|
1145
1133
|
},
|
|
1146
1134
|
{
|
|
1147
1135
|
"id": "local",
|
|
1148
1136
|
"title": "Build locally and send to Sprid",
|
|
1149
|
-
"summary": "Build content with your own tools, upload
|
|
1137
|
+
"summary": "Build content with your own tools, upload the finished files to Sprid, and keep editing, reviewing and measuring the same posts in chat or the dashboard.",
|
|
1150
1138
|
"url": "https://sprid.studio/docs/local",
|
|
1151
|
-
"markdown": "# Build locally and send to Sprid\n\n**What this guide does:** Build content with your own tools, upload
|
|
1152
|
-
"revision": "
|
|
1139
|
+
"markdown": "# Build locally and send to Sprid\n\n**What this guide does:** Build content with your own tools, upload the finished files to Sprid, and keep editing, reviewing and measuring the same posts in chat or the dashboard.\n\nTwo command families: `sprid media` is local production and file transfer (`init`, `build`, `check`, `register`, `push`, `preview`, `upload`). `sprid post` works on shared posts on the server. If sign-in fails, the local result stays usable. Keep the same post and plan IDs when you move work into Sprid.\n\n## Build\n\nUse your app’s own renderer or design tools, or a built-in recipe:\n\n```sh\nsprid media init # set up the stills or simulator-screen recipe\nsprid media build <slug>\nsprid media check <slug>\n```\n\nA TS/JS config runs local code, so only use one you trust. Native captures and binary builds need your app’s own environment. A local slug stays local; a shared preview is always `sprid post preview --id <postId>`.\n\n## Upload\n\n```sh\nsprid login\nsprid media upload slide-01.png slide-02.png --account my-account --json\n```\n\nFiles go straight to storage and come back as ordered asset IDs. PNG, JPEG, WebP and MP4, up to 32 MiB each; larger videos go through `sprid media push`. The command prints a request ID first. To resume, rerun with the same files in the same order and `--request-id <UUID>`, or read the saved result with `sprid media job <UUID>`. Don’t reuse a request ID for a different selection.\n\n## Create and review the post\n\nWrite `draft.json` with the returned IDs and a new UUID as `requestId` (keep it for retries):\n\n```json\n{\n \"account\": \"my-account\",\n \"requestId\": \"5e253644-d8a5-4b18-9cc9-d4d921874138\",\n \"title\": \"A concrete moment\",\n \"captionInstagram\": \"The caption, with hashtags at the end\",\n \"aspectRatio\": \"4:5\",\n \"presentation\": \"finished\",\n \"assets\": [{ \"kind\": \"image\", \"id\": 101 }, { \"kind\": \"image\", \"id\": 102 }]\n}\n```\n\nFor a finished reel, use one asset with `kind: \"video\"`. `finished` artwork gets no overlay or music; images fit inside the canvas, so check the preview for margins.\n\n```sh\nsprid post create --file draft.json --json\nsprid post get 123 --json\nsprid post update 123 --file changes.json --json # e.g. {\"captionInstagram\":\"Revised caption\"}\nsprid post preview --id 123 --json\nsprid post deliveries 123 --json\n```\n\nThe review link opens the same dashboard screen as from chat. To continue in chat, give it post ID `123` instead of creating another draft. Approval and platform choices stay with a person. Check delivery receipts before reporting success.\n\n## Hosted options and results\n\n- `sprid capabilities --json`: server limits and what stays local.\n- `sprid media import --file sources.json`: the same account/files/urls/assets payload as MCP `import_assets`.\n- `sprid media reel --file recipe.json`: the metered hosted reel. Payload and approval rules are in `sprid docs chat`. Poll with `sprid media job <UUID>`.\n- `sprid marketing-review`: connected evidence. `sprid docs marketing-review` covers coverage and attribution.\n\nKeys go in through CLI key-file commands or the secure Sprid forms, never a conversation.\n",
|
|
1140
|
+
"revision": "9fca88d8e62aa719"
|
|
1153
1141
|
},
|
|
1154
1142
|
{
|
|
1155
1143
|
"id": "marketing-review",
|
|
1156
1144
|
"title": "Review marketing from connected evidence",
|
|
1157
|
-
"summary": "Investigate acquisition, activation, retention and revenue through
|
|
1145
|
+
"summary": "Investigate acquisition, activation, retention and revenue through the services connected to Sprid, and say plainly what evidence is missing.",
|
|
1158
1146
|
"url": "https://sprid.studio/docs/marketing-review",
|
|
1159
|
-
"markdown": "# Review marketing from connected evidence\n\n**What this guide does:** Investigate acquisition, activation, retention and revenue through
|
|
1160
|
-
"revision": "
|
|
1147
|
+
"markdown": "# Review marketing from connected evidence\n\n**What this guide does:** Investigate acquisition, activation, retention and revenue through the services connected to Sprid, and say plainly what evidence is missing.\n\n## Start with the question\n\nName the app, the date range and the decision the review should inform.\n\n1. `list_apps` and `list_app_profiles` to find the app.\n2. `get_marketing_review_context` for shared definitions, required investigations, earlier decisions and corrections.\n3. `get_marketing_review` for the app over two comparable periods. The summary links to full evidence per source (`view: \"full\", sources: [<source>]`); omit `sources` to include social history, store reviews and milestones.\n4. Re-read an exact saved packet with `get_marketing_review_evidence` and its `evidence.id` (CLI: `sprid marketing-review evidence --id <id> --app <slug>`). It still works after a connection changes.\n\n`refresh: true` asks for live reads; `cachedOnly: true` reads only stored evidence. Keep returned errors, coverage, population definitions and sample counts in the report.\n\nIn a browser chat there is no repository. For a question about a shipped change, ask for a release summary or public changelog and label it as supplied. Never claim to have read a repository or private database. Local users can add repo diffs and database reads through their own tools.\n\n## Follow the evidence\n\n`list_marketing_queries` lists supported reads and their schemas; `query_marketing_source` runs them with Sprid’s saved credentials. Follow pagination and keep truncation visible. `get_documentation` with `metrics` covers definitions and refused calculations; with `queries`, source-specific reads.\n\n- Keep acquisition apart from activation, and people apart from events. A post impression is not an install; a download is not an activated user.\n- Compare equal windows and comparable populations.\n- No onboarding events means recommending instrumentation, not guessing a funnel.\n- Keep revenue sources separate until the overlap check says they can be added.\n\nFor each finding, test another explanation: tracking changes, traffic exclusions, attribution window, seasonality, a different audience mix. A before/after comparison doesn’t prove cause. If a difference is within normal variation or the sample is small, say so and don’t rank it.\n\n## Report and save\n\nLead with the decision, then the evidence, the limits and what would change the answer. Keep failed reads apart from reads that returned nothing. `next_actions` gives the follow-up. A missing credential goes to the secure App Profile form or a CLI key-file command; no provider MCP is needed for a supported query.\n\n- **Shared context:** when authorized, save non-secret definitions, investigations, decisions, corrections and release references with `save_marketing_review_context`, sending `baseRevision` from the latest read. A conflict returns both versions; reconcile before retrying. Saved context is a claim with references, not verification. CLI: `sprid marketing-review context --app <slug>` reads, `--file <context.json>` imports `{baseRevision,context}`. Private notes stay local.\n- **Changes:** log confirmed product or marketing changes with `add_event`, naming the areas they affect and why.\n- **The review itself:** save it as an app-scoped `kind: \"note\"` event with the date, conclusion, evidence references, coverage and next hypothesis in `meta`. Other clients read it with `list_events`. `log_reflection` is only for a post’s own statistics.\n\nNever store secrets or signed attachment URLs in any of these.\n\n## Collection and coverage\n\n- Sprid refreshes two rolling 30-day windows daily for configured services on active plans, and re-reads late provider exports. No model calls, publishing or paid social reads. Other windows are read on demand.\n- Pause with the App Profile’s `metricsCollectionEnabled: false` or `sprid marketing-review collection --enabled false`. Stored evidence stays readable.\n- Snapshots are private to the app, tied to its configuration and kept 90 days. Save local evidence exports for a lasting archive.\n- Missing days stay unknown. Incomplete store or Search Console windows get no percentage change. Never sum daily unique people into a monthly count.\n- `configuration_only` means identifiers and a key are saved, not that access works. Errors return a safe code, the HTTP status when known, whether to retry and the next step. Retry transient errors before recommending a reconnect. Unsupported metrics and provider privacy thresholds are stated as limits.\n",
|
|
1148
|
+
"revision": "71f8c7a54ea9307e"
|
|
1161
1149
|
},
|
|
1162
1150
|
{
|
|
1163
1151
|
"id": "traffic",
|
|
1164
1152
|
"title": "Check whether a traffic spike is real",
|
|
1165
|
-
"summary": "Tells you how to judge a sudden jump in website visitors, and how to remove a scraper from your numbers without removing customers. Read it before you act on a spike
|
|
1153
|
+
"summary": "Tells you how to judge a sudden jump in website visitors, and how to remove a scraper from your numbers without removing customers. Read it before you act on a spike or explain one.",
|
|
1166
1154
|
"url": "https://sprid.studio/docs/traffic",
|
|
1167
|
-
"markdown": "# Check whether a traffic spike is real\n\n**What this guide does:** Tells you how to judge a sudden jump in website\nvisitors, and how to remove a scraper from your numbers without removing\ncustomers. Read it before you act on a spike
|
|
1168
|
-
"revision": "
|
|
1155
|
+
"markdown": "# Check whether a traffic spike is real\n\n**What this guide does:** Tells you how to judge a sudden jump in website\nvisitors, and how to remove a scraper from your numbers without removing\ncustomers. Read it before you act on a spike or explain one.\n\nA spike is not proof of a bot, and a quiet baseline is not proof of people.\nGet it wrong one way and you chase a channel that never existed; the other way\nand you drop real readers from your own numbers. Use the four reads below, in\norder, and keep any rule as narrow as your evidence.\n\nSprid flags candidates. When one day carries at least 35% of a 30-day period\nand runs at ten times the median day, `next` shows **Review that day** with the\ndate, the multiple and that day’s pageviews per visitor against the rest of the\nmonth. It is a prompt, not a verdict: a daily series can’t tell a crawl from a\ngood day.\n\n## Four reads, in order\n\n**1. Find the hours, not the day.** Split the suspect day by hour. Marketing\narrives across a day and decays over several. A scrape is a block: a flat rate\nfor a few hours, then nothing. If the day’s total sits in four consecutive\nhours with ordinary hours either side, it is one client, not an audience.\n\n**2. Divide pageviews by visitors, but don’t trust it alone.** A browser with no\ncookie is a new visitor on every request, so a crawl that reads each page once\nshows a huge visitor count at 1.0 pageviews each. A crawler that hits each URL\nseveral times doesn’t: the September 2026 scrape ran at **1.60 pageviews a\nvisitor against a baseline of 1.44**. A flat 1.0 is suspicious; a healthy ratio\nproves nothing.\n\n**3. Ask for whole groups, not separate dimensions.** `review_traffic` returns\ncompound groups (browser, version, OS, screen, timezone, referrer, country\ntogether), because adding up separate dimension counts double-counts everyone.\nOne group carrying most of a day is the finding. Twelve groups sharing it evenly\nis not, unless they agree on something (below).\n\n**4. Look at which pages were hit.** A crawl walks your sitemap: every locale\nand item, a few hits each. Real discovery is lopsided: a few pages that rank or\nwere linked take most of the traffic.\n\n## What the fingerprint looks like\n\nRead the fields that are hardest to fake:\n\n- **Timezone against geography** is the strongest tell. A browser on\n `Asia/Shanghai` while its IPs sit in the US, Singapore and Germany is one\n operator on rented addresses. The addresses rotate; the machine’s clock\n doesn’t.\n- **An odd viewport** (`800x600`, `1512x982`, `1280x720`) beats the user agent,\n which is the field they bother to spoof. Expect a plausible current Chrome on\n macOS with a screen no customer has.\n- **A blend is a signature too.** One wave rotated Chrome 118-120, Edge 119-120\n and Firefox 120-121 so no browser stood out, all on one viewport, timezone and\n referrer. What they varied is noise; what they forgot to vary is the rule.\n- **Referrer `$direct`** on everything, with no search or social.\n- **Country is not a tell.** The same wave comes from a dozen countries. A\n country rule removes customers and keeps the scraper.\n\n## Check the comparison period too\n\nA percentage change has two periods, and nobody looks at the older one. On one\napp in September 2026 the same thirty days read **+252.5%** before review,\n**-62.6%** with only the obvious spike excluded, and **-17.6%** once two earlier\nwaves in the comparison period were excluded too. The middle answer was wrong\nand the most convincing, because it already looked corrected.\n\nSo when you find one wave, look for others before saving anything. Query the\nwhole history for its marker (the timezone, the viewport) by day. Waves have\nedges: 5 to 30 visitors a day in the background and several hundred on wave\ndays tells you where the rule starts and that the rest is ordinary.\n\n## Two more traps\n\n**Raw provider data is not what Sprid counted.** Web visitors already exclude\nevents with no browser, crawler and headless user agents, reported bots, and\nanything marked internal or test. A wave with a null browser never reached your\ntotal, so a raw query including it won’t match the card. Compare like with like\nor you exclude the same traffic twice.\n\n**Bound a rule by how ordinary its conditions are.** `1920x1080` is a real\nscreen many customers use, so a rule on it gets exactly the wave’s dates. A\nviewport nobody has can carry a longer window. The date range is the safety\nmargin for a condition that isn’t distinctive on its own.\n\n## Save the exclusion\n\nPreview, then save. `review_traffic` shows visitor counts before and after for\nthe period **and the one before it**, which is the number you want to see move.\n\n```json\n{\n \"id\": \"scrape-2026-09-18\",\n \"reason\": \"Full-site crawl 04:00-08:00 UTC: Asia/Shanghai timezone, 800x600 viewport, direct referrer, IPs across US/SG/DE. 39,958 of the day's 40,476 visitors, every locale and item page hit at most 5 times with no cookie reuse.\",\n \"start\": \"2026-09-18\",\n \"end\": \"2026-09-19\",\n \"enabled\": true,\n \"conditions\": [\n { \"field\": \"timezone\", \"value\": \"Asia/Shanghai\" },\n { \"field\": \"screenWidth\", \"value\": \"800\" },\n { \"field\": \"screenHeight\", \"value\": \"600\" }\n ]\n}\n```\n\n- End dates are exclusive and UTC.\n- Conditions in a rule are AND; separate rules are OR.\n- Fields: `browser`, `browserVersion`, `os`, `osVersion`, `screenWidth`,\n `screenHeight`, `timezone`, `referrer`, `country`. Values are exact strings;\n a missing property never matches.\n- Write `reason` for someone reading it in a year: the window, the evidence and\n how much it removes.\n\nSave through `upsert_app_profile` or `PATCH /api/app-profiles/:id` under\n`posthogConfig.trafficExclusions`, keeping the rest of the configuration. Then\n**log the change as an event** with the areas it affects and why, or next\nmonth’s drop in your graph becomes a new mystery.\n\n## What an exclusion doesn’t touch\n\nYour provider’s data is never changed or deleted; Sprid filters when it reads.\nApp activity, registrations and revenue are unaffected, since a scraper doesn’t\nsign up. Raw connected queries and the marketing-review event inventory stay\nunfiltered on purpose, as the evidence to check the rule against. **Restore this\ntraffic** disables a rule and the original numbers come straight back.\n\n## When not to exclude\n\nA spike with a real referrer and lopsided pages is a link that worked: find it\nbefore you filter it. A shared office machine, an uptime probe and a preview\nrenderer all repeat a fingerprint, and none is worth a rule. A group you can’t\nexplain stays in: an unexplained visitor counted is a smaller error than a\ncustomer removed.\n",
|
|
1156
|
+
"revision": "2ee50917e61c94f4"
|
|
1169
1157
|
},
|
|
1170
1158
|
{
|
|
1171
1159
|
"id": "pinterest-content",
|
|
1172
1160
|
"title": "Pinterest content and publishing",
|
|
1173
1161
|
"summary": "Plan searchable Pins, approve a useful batch, let Sprid publish the selected Pins on schedule and judge the result by qualified traffic and activation.",
|
|
1174
1162
|
"url": "https://sprid.studio/docs/pinterest",
|
|
1175
|
-
"markdown": "# Pinterest content and publishing\n\n**What this guide does:** Plan searchable Pins, approve a useful batch, let Sprid publish the selected Pins on schedule and judge the result by qualified traffic and activation.\n\nChecked against Pinterest’s current guidance on 21 September 2026. Recommendations labelled as tests are starting hypotheses, not claims about what will win for your account.\n\n## How Pinterest discovery works\n\nPinterest works as a visual search and recommendation system. A Pin can appear in search, home feeds and related recommendations long after publication. Discovery does not depend primarily on followers.\n\nPinterest says relevance comes from signals in the Pin and how people interact with it. Clear keywords, original imagery, link quality and relevant board context help Pinterest understand the subject; Pinterest does not publish a fixed weighting for them. Give one coherent answer to “what is this about?” across the visual, title, description, board and landing page. Use the language a person would search, without repeating a keyword unnaturally.\n\nPins can remain discoverable after publication. Compare results at equal Pin ages, and keep older useful Pins in the analysis instead of treating the first day as the full result.\n\n## Start with the destination\n\nChoose the page and desired user action before making the visual:\n\n1. Pick one useful guide, tool, feature page or store destination.\n2. State the concrete question it answers.\n3. Choose one action that continues the same task, such as opening the relevant feature or starting its setup.\n4. Add campaign parameters without deleting existing URL parameters. Use a stable Pin or creative identifier so visits can be traced back to the exact Pin.\n\nThe destination must deliver the pictured promise immediately and work well on a phone. A specific Pin leading to a generic homepage usually breaks that promise. A store visit is not an install, and an outbound click is not activation; keep each step separate in reporting.\n\n## Choose topics and boards\n\nUse Pinterest Trends, Pinterest search suggestions, customer language and proven site queries to build a topic list. Search Console is a useful seed, but Google demand does not prove Pinterest demand.\n\nMix evergreen questions with relevant seasonal moments. Use a focused board whose name and description explain the topic. A Pin about apartment-viewing costs belongs on a board about buying an apartment, not a broad “Ideas” board. Create a new board only when the topic will support a useful collection.\n\n## Choose a cadence to test\n\nSprid recommends **2 original Pins per day as an initial experiment**, spread across separate slots. With a broad catalog of useful destinations and genuinely distinct assets, test **5 per day** against that baseline. These are proposed test settings, not Pinterest limits or proven optima. A limited destination library calls for expanding useful content, not filling the queue with cosmetic duplicates.\n\nCreate and review batches together, then spread publication across the calendar. Rotate destination pages and topics. Start with two distinct creative treatments per destination; space those treatments across different days. Neither an exact spacing interval nor a universal best hour is established by the evidence reviewed.\n\nPinterest itself recommends original content at least weekly. Marketer examples range from one daily Pin to several: [Sarah Hanford](https://www.sarahhanford.com/blog/pinterest-growth-organically-60-days) reports moving from three daily to five, alongside keyword research and a new website. That does not isolate frequency as the cause of growth.\n\n[Tailwind’s benchmark](https://www.tailwindapp.com/pinterest-marketing/research/2025-benchmark-study-part-1) covered approximately 1.2 million organic Pins, using 2024 data. Results were concentrated in a small share of Pins. Its English-speaking customer sample and observational design cannot establish a universal cadence or predict another market’s conversions.\n\nReview cohorts at 30, 60 and 90 days of Pin age. Change one variable per test and repeat across comparable destinations. Keep higher frequency when additional Pins repeatedly produce additional qualified visits or activations; a lower click rate alone does not invalidate growth in total qualified traffic. Report counts and coverage, including results with the leading Pin removed, so one outlier cannot determine the strategy.\n\n## Build the Pin\n\nFor an image Pin, use **2:3**, ideally **1000 × 1500 px**. For full-screen video, use **9:16**, ideally **1080 × 1920 px**. Pinterest currently allows organic video from **4 seconds to 5 minutes** with H.264 or H.265 encoding.\n\nSprid publishes one selected image or one finished video per Pin. It does not silently turn a multi-slide Instagram carousel into a Pinterest Pin. Prepare a dedicated Pinterest asset and inspect its crop in the preview.\n\nAt feed-thumbnail size, the subject and benefit should still be clear. Use one visual focus, strong contrast and brief readable overlay copy. Check the real phone preview. The Pin must stand alone; an Instagram opener that only makes sense after swiping to slide two is incomplete here.\n\nUseful formats to test include:\n\n- an editorial cover for a specific guide;\n- a reference card with a concrete checklist or answer;\n- a real product or app demonstration showing one task;\n- a coherent visual collection for design, travel or architecture;\n- a short captioned video when motion explains the task better than a still.\n\nPinterest can label detected or declared AI imagery. Preserve provenance, use accurate licensed assets and make any required disclosure. Never publish an image that misrepresents the linked place, product or result.\n\n## Write the metadata\n\nOrganic Pin titles allow **100 characters**. Put the useful subject early because only part of the title may appear in a feed. Descriptions allow **800 characters**. Descriptions may be hidden in home and search feeds, but Pinterest uses them to understand relevance.\n\nAlt text allows **500 characters** in the Pinterest API. Describe what the visual shows for someone who cannot see it; do not use alt text as another keyword field. Choose an AI disclosure in Sprid when it applies to the asset.\n\nWrite a natural title and description that name the topic, audience or situation and what the destination provides. Choose a relevant board and add a working destination. Do not stuff variants of the same keyword, use unrelated trends or promise something the page does not deliver.\n\nThe visual earns attention; metadata supplies context; the destination completes the task. Keep all three aligned.\n\n## Publish your first Pin\n\nPublishing and scheduling require Sprid’s Pinterest app to have Standard access. With Trial access, you can connect the account, browse boards and prepare drafts, but Sprid will refuse the publish or schedule request. This access tier belongs to Sprid’s integration; the customer does not apply for a developer app.\n\n1. Connect Pinterest, then run `sprid status` and confirm the intended account.\n2. Create or open a post with exactly one image, preferably at 2:3, or one finished video, preferably at 9:16.\n3. Open **Publish**, select **Pinterest**, then choose a **Board** and optional section.\n4. Add the Pin title, description, destination, alt text and any AI disclosure.\n5. Inspect the rendered creative and every public field. Publish now or choose a future time.\n6. After delivery, open the Pin while signed out or from another account and follow its destination.\n\nIn the CLI, use `sprid pinterest boards --account <slug>` to find board IDs. If there are none, it says so; create one with `sprid pinterest create --account <slug> --name <name> [--privacy public|secret]`. Then use `sprid pinterest set <postId> --board <id> --link <url>` with the optional metadata flags shown by `sprid docs cli`. The command saves the draft; review and schedule it in Sprid. Later, `sprid pinterest metrics <publishId> --account <slug>` reads a bounded results window.\n\nWith MCP, read `get_documentation` topic `pinterest-content`, select the exact channel from `list_connections`, then call `list_pinterest_boards`. If it returns no boards, say so and call `create_pinterest_board` only with a user-approved name and privacy. Save `pinterestOptions` with `update_post`. Prefer `aspectRatio: \"2:3\"` for a new image Pin. Render the preview, show the user the specific Pin or dry-run batch, then call `schedule_post` or commit `schedule_batch` only for the Pins they selected. Use `get_pinterest_metrics` for results.\n\n## Review and schedule in Sprid\n\nFor a two-Pin daily test, choose **Daily** and two separate times in the batch scheduler. For example, **09:00 and 17:00** are convenient slots, not researched best posting times. Check the returned account timezone and the actual dates before confirming; do not assume they match your device. Keep an existing user-chosen cadence unless they ask to change it.\n\nOrder the selected Pins so different destinations alternate. Review the calendar preview for occupied days, gaps and any unplaced Pins. A large batch is fine to prepare at once; its publication can be spread across the schedule.\n\nFor MCP, use `schedule_batch` with `cadence: \"daily\"`, `times: [\"09:00\", \"17:00\"]`, the chosen account/channel and selected post IDs. Start with `dryRun: true`, then inspect `placements`, `unplaced` and `timezone`. Busy days are skipped by default, so check the returned plan rather than promising a fixed completion date. Commit only the reviewed selections and report what was actually booked. CLI users can read this guide with `sprid docs pinterest-content` and review the queue with `sprid queue`; use the scheduling UI or connected MCP tools to place the batch.\n\nA time-only move keeps the reviewed creative and destination. If you change a scheduled Pin’s content, board or link, review and reschedule the updated Pin. Changed drafts can be blocked at publication until reviewed again. After an ambiguous publishing failure, check Pinterest before retrying because the original Pin may already exist.\n\nReview every selected Pin’s rendered creative, public metadata, destination, board and scheduled time. Check factual claims, rights and disclosure before approving the batch.\n\nPinterest’s published developer guidelines require the user to choose each Pin that will be published. Sprid implements that rule by showing the concrete Pins and their schedule, then recording the user’s batch selection. Those selected Pins publish automatically at their scheduled times; the user does not return to approve the same unchanged schedule again. Review any new or edited Pin before adding it to a schedule.\n\nAfter the first scheduled Pin publishes, verify its public visibility and destination from outside the connected Pinterest account. A draft, preview or accepted schedule is not proof of delivery.\n\n## Measure what happened\n\nKeep Pinterest’s metrics distinct:\n\n- **Impressions:** times the Pin was on screen.\n- **Saves:** times people saved it to a board.\n- **Pin clicks:** clicks that opened the Pin in close-up.\n- **Outbound clicks:** actions leading to a destination outside Pinterest.\n- **Video views:** at least 2 seconds with at least 50% of the video in view.\n\nFor app growth, the useful path is **impression → outbound click → qualified landing visit → app action → activation**. Use saves as a diagnostic, not the final success metric. A Pin with many saves and few outbound clicks may be valuable as an on-platform reference while contributing little acquisition.\n\nCompare Pins of similar age within the same topic, language and market. Judge creative using outbound-click rate and qualified visits; judge the whole path using activations per Pin and, where available, revenue. Pinterest-reported outbound clicks and first-party website sessions use different measurement methods, so show both rather than forcing them to match.\n\nIf visits arrive but activation does not, inspect page speed, message match and the next app action before making more Pins. If impressions are low, inspect topic relevance, board context, metadata and visual clarity. If qualified traffic and activation remain negligible across repeated relevant cohorts, stop scaling that app’s Pinterest output.\n\n## Improve the next batch\n\nChange one meaningful element within a comparison: visual treatment, question, format or destination angle. Organic distribution is not randomized, so call the result a directional test, not a controlled A/B experiment.\n\nCreate fresh, useful treatments rather than cosmetic duplicates. [Tailwind’s freshness study](https://www.tailwindapp.com/pinterest-marketing/research/2025-benchmark-study-part-three) found stronger retained distribution from new images for an existing URL than from repeatedly reusing the same image and URL; this is association, not a guaranteed lift. Pinterest advises against repeatedly uploading the same Pin, and repetitive or irrelevant commercial content can be treated as spam. Spread treatments of the same destination apart and keep every Pin on a relevant board.\n\nUse the next review to choose topics and destinations for another test. For example, [Elaine Timms’s recipe-client case](https://elainetimms.com/evergreen-growth-how-food-creator-pins-for-profit/) combines search-specific overlays, creative variants and email opt-ins. Adopt the connected workflow; its reported growth cannot be attributed to cadence alone.\n\n## Prepare the website\n\nClaim an owned website in Pinterest to associate the profile with Pins from that domain and expand website analytics. One website can be claimed by only one Pinterest account.\n\nFor eligible articles, products or recipes, add the relevant Open Graph or Schema.org metadata for Rich Pins. Rich Pins synchronize information from the page; they are website metadata, not a separate Sprid export. Check how that metadata appears before publishing a batch because a manual Pin edit can override synced article or recipe information.\n\nMake sure Pinterestbot can read the destination, links work and pages load quickly on mobile. Preserve any existing URL parameters when adding attribution.\n\n## Sources\n\n- [How Pinterest discovery works](https://create.pinterest.com/blog/how-to-increase-discoverability-seo-pinterest/)\n- [Growing through search, boards and keywords](https://create.pinterest.com/blog/best-ways-to-grow-on-pinterest/)\n- [Pin specifications](https://help.pinterest.com/en/article/review-pin-specs)\n- [Pin performance and distribution](https://help.pinterest.com/en/business/article/pin-performance-and-distribution)\n- [Pinterest Analytics definitions](https://help.pinterest.com/en/business/article/pinterest-analytics)\n- [Pinterest developer guidelines](https://policy.pinterest.com/en/developer-guidelines)\n- [Pinterest API schema](https://github.com/pinterest/api-description/blob/main/v5/openapi.json)\n- [Pinterest community guidelines](https://policy.pinterest.com/en/community-guidelines)\n- [Pinterest labels for AI-generated or modified images](https://help.pinterest.com/en/article/gen-ai-labels)\n- [Claim your website](https://help.pinterest.com/en/business/article/claim-your-website)\n- [Rich Pins](https://help.pinterest.com/en-gb/business/article/rich-pins)\n",
|
|
1176
|
-
"revision": "
|
|
1163
|
+
"markdown": "# Pinterest content and publishing\n\n**What this guide does:** Plan searchable Pins, approve a useful batch, let Sprid publish the selected Pins on schedule and judge the result by qualified traffic and activation.\n\nChecked against Pinterest’s guidance on 21 September 2026. Anything labelled a test is a starting hypothesis, not a claim about what will win for your account.\n\n## How Pinterest discovery works\n\nPinterest is visual search and recommendation. A Pin can show up in search, home feeds and related Pins long after it is published, mostly regardless of followers.\n\nRelevance comes from the Pin itself and how people interact with it: clear keywords, original imagery, link quality and board context. Pinterest publishes no weighting. Make the visual, title, description, board and landing page all answer the same “what is this about?”, in the words a person would search, without repeating a keyword unnaturally.\n\nBecause Pins keep getting found, compare them at equal ages and keep older Pins in the analysis.\n\n## Start with the destination\n\nPick the page and the action before making the visual:\n\n1. One useful guide, tool, feature page or store destination.\n2. The concrete question it answers.\n3. One next action that continues the same task, such as opening that feature.\n4. Campaign parameters added without removing existing ones, with a stable Pin or creative ID so visits trace back to the exact Pin.\n\nThe page must deliver the pictured promise immediately and work on a phone. A specific Pin that lands on a generic homepage breaks the promise. A store visit is not an install, and an outbound click is not activation: report each step separately.\n\n## Prepare the website\n\n- **Claim your website** in Pinterest to link the profile to Pins from that domain and get website analytics. A website can be claimed by only one Pinterest account.\n- **Rich Pins:** for articles, products or recipes, add Open Graph or Schema.org metadata. Pinterest syncs it from the page; it is not a Sprid export. Check how it appears before a batch, because editing a Pin by hand can override synced article or recipe details.\n- Make sure Pinterestbot can read the page, links work and it loads fast on mobile.\n\n## Choose topics and boards\n\nBuild the topic list from Pinterest Trends, Pinterest search suggestions, customer language and site queries that already work. Search Console is a useful seed, but Google demand doesn’t prove Pinterest demand.\n\nMix evergreen questions with relevant seasonal moments. Use focused boards whose name and description explain the topic: a Pin about apartment-viewing costs belongs on a board about buying an apartment, not a broad “Ideas” board. Only create a board when the topic can fill it.\n\n## Build the Pin\n\n| | Ratio | Ideal size | Notes |\n|---|---|---|---|\n| Image | 2:3 | 1000 × 1500 px | |\n| Video | 9:16 | 1080 × 1920 px | 4 seconds to 5 minutes, H.264 or H.265 |\n\nSprid publishes one image or one finished video per Pin. It never turns an Instagram carousel into a Pin, so make a dedicated asset and check its crop in the preview.\n\nAt thumbnail size the subject and benefit should still be clear: one focus, strong contrast, short readable overlay copy. Check the real phone preview. The Pin must stand alone; an opener that only makes sense after swiping is incomplete here.\n\nFormats worth testing:\n\n- an editorial cover for a specific guide\n- a reference card with a concrete checklist or answer\n- a real app demo showing one task\n- a coherent visual collection for design, travel or architecture\n- a short captioned video when motion explains the task better\n\nPinterest can label detected or declared AI imagery. Keep provenance, use accurate licensed assets and disclose where required. Never publish an image that misrepresents the linked place, product or result.\n\n## Write the metadata\n\n| Field | Limit | Notes |\n|---|---|---|\n| Title | 100 characters | Put the subject early; feeds may cut it. |\n| Description | 800 characters | Often hidden in feeds, but Pinterest reads it for relevance. |\n| Alt text | 500 characters | Describe what the image shows. Not a keyword field. |\n\nWrite a natural title and description naming the topic, audience or situation and what the destination provides. Choose a relevant board, add a working destination, and set the AI disclosure in Sprid when it applies. No stuffed keyword variants, unrelated trends or promises the page doesn’t keep.\n\nThe visual earns attention, the metadata gives context, the destination completes the task. Keep all three aligned.\n\n## Publish your first Pin\n\nPublishing and scheduling need Sprid’s Pinterest app to have Standard access. With Trial access you can connect, browse boards and prepare drafts, but Sprid refuses to publish or schedule. That access belongs to Sprid’s integration; you don’t apply for a developer app.\n\n1. Connect Pinterest, run `sprid status` and confirm the account.\n2. Create or open a post with exactly one image (ideally 2:3) or one finished video (ideally 9:16).\n3. Open **Publish**, select **Pinterest**, then pick a **Board** and optional section.\n4. Add the title, description, destination, alt text and any AI disclosure.\n5. Check the rendered creative and every public field. Publish now or pick a time.\n6. After delivery, open the Pin signed out or from another account and follow its link.\n\n**CLI:** `sprid pinterest boards --account <slug>` lists board IDs, or says there are none; create one with `sprid pinterest create --account <slug> --name <name> [--privacy public|secret]`. `sprid pinterest set <postId> --board <id> --link <url>` saves the draft (optional metadata flags in `sprid docs cli`); review and schedule it in Sprid. `sprid pinterest metrics <publishId> --account <slug>` reads results.\n\n**MCP:** read `get_documentation` topic `pinterest-content`, pick the exact channel from `list_connections`, then `list_pinterest_boards`. If there are none, say so, and call `create_pinterest_board` only with a name and privacy the user approved. Save `pinterestOptions` with `update_post`, preferring `aspectRatio: \"2:3\"` for a new image Pin. Show the user the rendered Pin or dry-run batch, then call `schedule_post` or commit `schedule_batch` only for the Pins they chose. `get_pinterest_metrics` reads results.\n\n## Choose a cadence to test\n\nStart with **2 original Pins a day** in separate slots. With a broad catalog of useful destinations and genuinely distinct assets, test **5 a day** against that. These are Sprid’s proposed tests, not Pinterest limits or proven optimums. A small destination library needs more useful content, not cosmetic duplicates in the queue.\n\nRotate destinations and topics. Start with two distinct treatments per destination, on different days. No exact spacing or best hour is established.\n\nWhat the evidence says: Pinterest recommends original content at least weekly. [Sarah Hanford](https://www.sarahhanford.com/blog/pinterest-growth-organically-60-days) went from three Pins a day to five alongside keyword research and a new website, so frequency isn’t isolated as the cause. [Tailwind’s benchmark](https://www.tailwindapp.com/pinterest-marketing/research/2025-benchmark-study-part-1) of about 1.2 million organic Pins (2024 data) found results concentrated in a small share of Pins; its English-speaking, observational sample can’t set a universal cadence.\n\n## Review and schedule the batch\n\nFor a two-a-day test, choose **Daily** and two times in the batch scheduler, for example **09:00 and 17:00** (convenient, not researched best times). Check the account’s timezone and the actual dates before confirming; they may differ from your device. Keep a cadence the user already chose unless they ask to change it.\n\nOrder Pins so destinations alternate, and check the calendar preview for busy days, gaps and unplaced Pins. Preparing a large batch at once is fine; publication spreads across the schedule.\n\n**MCP:** `schedule_batch` with `cadence: \"daily\"`, `times: [\"09:00\", \"17:00\"]`, the account/channel and the selected post IDs. Run `dryRun: true` first and check `placements`, `unplaced` and `timezone`. Busy days are skipped by default, so read the returned plan instead of promising an end date. Commit only the reviewed Pins and report what was booked. CLI users read this guide with `sprid docs pinterest-content` and the queue with `sprid queue`; place batches in the scheduling screen or over MCP.\n\nBefore approving, check every Pin’s creative, metadata, destination, board and time, plus factual claims, rights and disclosure. Pinterest’s developer guidelines require the user to choose each Pin that publishes: Sprid shows the concrete Pins and schedule and records the selection. Those Pins then publish on time without asking again.\n\n- Moving only the time keeps the reviewed Pin. Changing content, board or link means reviewing and rescheduling it; changed drafts can be blocked at publish until reviewed.\n- After an unclear publish failure, check Pinterest before retrying; the Pin may already exist.\n- After the first Pin publishes, check it and its link from outside the connected account. A draft, preview or accepted schedule is not delivery.\n\n## Measure what happened\n\n- **Impressions:** times the Pin was on screen.\n- **Saves:** times people saved it to a board.\n- **Pin clicks:** opens of the Pin in close-up.\n- **Outbound clicks:** clicks through to a destination outside Pinterest.\n- **Video views:** at least 2 seconds with at least 50% of the video in view.\n\nFor app growth the path is **impression → outbound click → qualified visit → app action → activation**. Saves are a diagnostic, not the goal: a Pin with many saves and few outbound clicks may be a good reference on Pinterest and bring little acquisition.\n\nCompare Pins of similar age within the same topic, language and market. Judge creative by outbound-click rate and qualified visits, the whole path by activations per Pin and revenue where available. Pinterest’s outbound clicks and your own site sessions are measured differently; show both rather than forcing them to match.\n\nReview cohorts at 30, 60 and 90 days of Pin age. Report counts and coverage, including results with the top Pin removed, so one outlier can’t set the strategy. Keep a higher frequency while extra Pins keep adding qualified visits or activations; a lower click rate alone doesn’t cancel growth in total qualified traffic.\n\n- Visits but no activation: check page speed, message match and the next app action before making more Pins.\n- Low impressions: check topic relevance, board, metadata and visual clarity.\n- Negligible qualified traffic and activation across repeated relevant cohorts: stop scaling Pinterest for that app.\n\n## Improve the next batch\n\nChange one meaningful thing per comparison (visual treatment, question, format or destination angle) and repeat across comparable destinations. Organic distribution isn’t randomized, so call it a directional test, not an A/B test.\n\nMake fresh, useful treatments, not cosmetic duplicates. [Tailwind’s freshness study](https://www.tailwindapp.com/pinterest-marketing/research/2025-benchmark-study-part-three) found new images for an existing URL kept distribution better than reusing the same image and URL (an association, not a guaranteed lift). Pinterest advises against re-uploading the same Pin, and repetitive or irrelevant commercial content can be treated as spam. Space treatments of the same destination apart and keep every Pin on a relevant board.\n\nFor a worked example, [Elaine Timms’s recipe-client case](https://elainetimms.com/evergreen-growth-how-food-creator-pins-for-profit/) combines search-specific overlays, creative variants and email opt-ins. Its growth can’t be credited to cadence alone.\n\n## Sources\n\n- [How Pinterest discovery works](https://create.pinterest.com/blog/how-to-increase-discoverability-seo-pinterest/)\n- [Growing through search, boards and keywords](https://create.pinterest.com/blog/best-ways-to-grow-on-pinterest/)\n- [Pin specifications](https://help.pinterest.com/en/article/review-pin-specs)\n- [Pin performance and distribution](https://help.pinterest.com/en/business/article/pin-performance-and-distribution)\n- [Pinterest Analytics definitions](https://help.pinterest.com/en/business/article/pinterest-analytics)\n- [Pinterest developer guidelines](https://policy.pinterest.com/en/developer-guidelines)\n- [Pinterest API schema](https://github.com/pinterest/api-description/blob/main/v5/openapi.json)\n- [Pinterest community guidelines](https://policy.pinterest.com/en/community-guidelines)\n- [Pinterest labels for AI-generated or modified images](https://help.pinterest.com/en/article/gen-ai-labels)\n- [Claim your website](https://help.pinterest.com/en/business/article/claim-your-website)\n- [Rich Pins](https://help.pinterest.com/en-gb/business/article/rich-pins)\n",
|
|
1164
|
+
"revision": "563dbb5a9c4b3053"
|
|
1177
1165
|
}
|
|
1178
1166
|
];
|