Handle .measure
Read any public account’s followers, engagement rate and posting cadence from its last 30 posts, before you sponsor it, pitch it or copy it.
- Price
- 19¢ per 100 accounts
- Success rate
- 99.9% of 413,075 calls
- Freshness
- Fresh for 7 days
- Emits
Handle.measured
Inputs
Outputs
| Field | Type | What null means |
|---|---|---|
measures | Measure[] | Never null: one row for each account read; a private or gone account is left out, free. What it means lastPostAt over 30 days ago: The account has gone quiet; its follower count is history. Do not pay for a spot; pick an account that posted this week. Planning estimate.Under half the median of the accounts you compared: The audience is bought or tired. Drop it from a sponsorship shortlist. Planning estimate. Under 5% of followers on a video Venue: The Venue stopped showing its posts widely. Price a sponsorship from median views, never from followers. Planning estimate. |
measures[].handle | string | Never null: the account as the Venue names it, @smalllandlordmath. |
measures[].followers | number | null, in followers or subscribers | The Venue counts none: Reddit. |
measures[].following | number | null | The Venue shows none: YouTube. |
measures[].postsRead | number, in posts | Never null: the posts the averages are over. |
measures[].engagementRate | number | null, in 0 to 1: reactions and comments a post over followers, averaged | Fewer than 10 posts read, or no follower count. |
measures[].medianViews | number | null, in views a post | The Venue shows no views: LinkedIn, Reddit. |
measures[].cadence | { postsPerWeek: | Never null. lastPostAt is null for an account that never posted. |
measures[].topPosts | { url: | Never null: the three posts with the most engagement among those read. |
measures[] | Observed | Each row also carries observedAt, method and venue. |
cost | Cost, in USD | Never null. In try mode usd is 0 and maxUsd is what the call would have cost. |
On each Venue
| Venue | What comes back | Limits | Price |
|---|---|---|---|
Followers, following, engagement rate and cadence; medianViews from reels. | A private account is skipped, free. | About 19¢ per 100 accounts | |
| TikTok | Followers, following, engagement rate, cadence and medianViews. | None. | About 9¢ per 100 accounts |
| YouTube | Subscribers as followers, engagement rate, cadence and medianViews; following is null. | None. | About 19¢ per 100 accounts |
| X | Followers, following, engagement rate, cadence and medianViews where X shows views. | Replies are left out of cadence; reposts count. | About 7¢ per 100 accounts |
| Followers, engagement rate and cadence of a member or company page; no views. | The dearest Venue to measure, at about 0.34¢ an account. | About 34¢ per 100 accounts | |
Cadence and engagement of an account’s posts and comments; followers is null. | Engagement is score per post, never a share of followers. | About 10¢ per 100 accounts | |
| A page’s followers and cadence; engagement rate from public posts. | Pages only, never personal profiles. | About 19¢ per 100 accounts | |
| Hacker News | Nothing: no route reads Hacker News accounts yet. | Refuses with venue-unsupported. | None. |
Effects
- Action class
None: it reads, so no approval rule names it
- Modes
try: Runs the read and returns real rows; nothing is saved and nothing is billed.send: Returns a pending Action at once; its Event carries the rows when the read finishes.do: Waits for the read and returns the rows, billed per result.
- Idempotency
The same
Idempotency-Keywith the same input replays the first answer at $0; with other input it returns 409.- Saved or shared
Nothing is written to your records. A reading is shared across startups for the same account for 7 days; it reads public accounts only.
- Emits
Handle.measuredwith{ venue,measures } - Performed by
- Price
About 19¢ per 100 accounts. At most 34¢ per 100 accounts. Free: an account that is gone or private, a reading younger than
maxAge.maxCostdefaults to 10¢. Ten shortlisted accounts, measured before you pick two: 10 × 0.19¢ an account is about 1.9¢.- Reliability
The first route succeeds 99.9% of 413,075 calls. If it fails, the call refuses with
sources-busyand nothing is spent.- Freshness
A reading younger than 7 days returns at $0. Readings are shared across startups for the same subject and locale.
- Batch and pages
Up to 25 accounts a call. It answers in one response.
- Rate
The shared rate rules: 10 calls a second per key, and an array input counts as one call.
- Capability
Refuses when
| Check | Error | Fix | Then call |
|---|---|---|---|
A search engine, answer engine or network the call does not read, such as ChatGPT sent to Keyword.measure | venue-unsupported | Pick one the call’s venue input lists; AI answers are Keyword.ask, posts are Keyword.search. | Keyword.ask |
Every data call can also meet the shared data-call refusals: filter-unsupported, input-missing, limit-exceeded, max-cost, rate-limited, sources-busy.
The venue-unsupported payload
{
"type": "https://startupbuilder.dev/errors/venue-unsupported" ,
"title": "The call does not read that search engine or network",
"status": 422,
"detail": "A search engine, answer engine or network the call does not read, such as ChatGPT sent to `Keyword.measure`." ,
"fix": "Pick one the call’s `venue` input lists; AI answers are `Keyword.ask`, posts are `Keyword.search`." ,
"next": {
"verb": "Keyword.ask",
"input": {
"keyword": "best rent tracking software for a 40-unit property manager",
"venues": [
"chatgpt"
]
}
},
"instance": "https://api.sb/leaseline.app/actions/action_1"
}When it waits
Returns in one response; nothing waits.
Example
A batch: three accounts in one call, one price cap, one cost. The private account is left out and costs nothing.
Compare @smalllandlordmath, @rentrollreview and @closedaccount on
YouTube; spend up to 2¢. {
"measures": [
{
"venue": "youtube",
"handle": "@smalllandlordmath",
"followers": 41200,
"following": null,
"postsRead": 30,
"engagementRate": 0.046,
"medianViews": 6800,
"cadence": {
"postsPerWeek": 1.5,
"lastPostAt": "2026-10-23T15:00:00Z"
},
"topPosts": [
{
"url": "https://www.youtube.com/watch?v=rentroll40" ,
"engagement": {
"views": 61000,
"reactions": 2400,
"comments": 310
}
}
],
"observedAt": "2026-10-27T14:02:11Z" ,
"method": "sampled"
},
{
"venue": "youtube",
"handle": "@rentrollreview",
"followers": 128000,
"following": null,
"postsRead": 30,
"engagementRate": 0.009,
"medianViews": 3100,
"cadence": {
"postsPerWeek": 0.5,
"lastPostAt": "2026-09-02T18:00:00Z"
},
"topPosts": [
{
"url": "https://www.youtube.com/watch?v=rentroll2019" ,
"engagement": {
"views": 22000,
"reactions": 410,
"comments": 52
}
}
],
"observedAt": "2026-10-27T14:02:11Z" ,
"method": "sampled"
}
],
"cost": {
"usd": 0,
"maxUsd": 0.0057,
"units": 2,
"misses": 1
}
}To retry, send the same Idempotency-Key: the retry returns the first answer for $0. A new key reads again.
Test values, and watching it
A sk_test_ key answers these the same way every time, at $0 (every test value).
| Test value | Always returns | What it is for |
|---|---|---|
@smalllandlordmath | {"followers": | Measures the same channel every time: 41,200 subscribers, 4.6% engagement, a video and a half a week. |
maxCost: | Refuses with max-cost | Any priced call with a maxCost of 0.0001 is refused before it spends: the price is above the cap. |
rate-limited.test | Refuses with rate-limited | Any call naming this hostname answers 429 with Retry-After, so your retry logic runs. |
sources-busy.test | Refuses with sources-busy | Any call naming this hostname answers 503 as if every route were busy, and nothing is spent. |
Watch it on a schedule: a Monitor runs this call and records an Event only when the reading changes.
await $.Monitor.create({
verb: 'Handle.measure',
input: { handles: ['@smalllandlordmath'], venue: 'youtube' },
change: 'engagement-drop',
threshold: 0.2,
every: '1w',
})Used by
None.