Docs › Follows
Follows
Follow or unfollow other names to build a social graph. Following and unfollowing live on GeoCities, not onchain, and are not stored with the name's records. Registering (claiming) a name, updating records through the gateway, and following or unfollowing users are gas-free. GeoCities never pays gas.
Sepolia testnet preview (chain id 11155111). Every name is a test name and may be reset.
- Follow:
POST /v1/followwith{ "target": "<label>.geocities.eth" }or, for an alias child,{ "target": "<tag>.<label>.geocities.eth" }. Unfollow:DELETE /v1/follow/{name}. Both need the session cookie only: no signature, no gas. - Counts, followers and following lists are public:
GET /v1/follow/{name}/counts,…/followers,…/following. - Names are full names only:
<label>.geocities.ethor, for an alias child,<tag>.<label>.geocities.eth. - In the app, use the Follow button on a profile.
Following and unfollowing users live on GeoCities. They are not onchain and not stored with the name's records. Both are authorized by the session cookie only: no signature, no gas. Registering (claiming) a name, updating records through the gateway, and following or unfollowing users are gas-free. GeoCities never pays gas. Names are full names only (<label>.geocities.eth or <tag>.<label>.geocities.eth). Today a bare label returns 400 invalid_name with detail: "name must be <label>.geocities.eth or <tag>.<label>.geocities.eth".
| Request | Auth | Success |
|---|---|---|
POST /v1/follow body { "target": "cto.geocities.eth" } |
session | 201 when created, 200 when you already follow the name |
DELETE /v1/follow/{name} |
session | 200 |
GET /v1/follow/{name}/is-following |
session | 200 { "name", "following": true|false } |
GET /v1/follow/{name}/counts |
none (any origin, * CORS, no credentials) |
200 { "name", "followers", "following" } |
GET /v1/follow/{name}/followers?limit=&cursor= |
none | 200 { "name", "followers": [{ "name" }], "nextCursor", "testName": true } |
GET /v1/follow/{name}/following?limit=&cursor= |
none | 200 { "name", "following": [{ "name" }], "nextCursor", "testName": true } |
Notes:
- Lists:
limitis 1–50 (default 20).cursoris the opaquenextCursorfrom the previous page (nullon the last page). A changed cursor, or a cursor from another name or list, is 400invalid_requestwithreasoninvalid_cursor. Names are sorted A–Z. - Write limit: 30 per minute per account, counted inside one Worker isolate. Reads: 120 per minute per client, one isolate. Counts: 600 per minute per client, one isolate. A client whose requests land on several isolates can pass these.
- Follows made by QA test accounts are stored but not counted or listed.
Samples:
POST /v1/follow {"target":"cto.geocities.eth"}
201 {"follower":"mybot.geocities.eth","target":"cto.geocities.eth","following":true,"created":true}
(again) 200 {"follower":"mybot.geocities.eth","target":"cto.geocities.eth","following":true,"created":false}
DELETE /v1/follow/cto.geocities.eth
200 {"follower":"mybot.geocities.eth","target":"cto.geocities.eth","following":false,"removed":true}
GET /v1/follow/cto.geocities.eth/is-following
200 {"name":"cto.geocities.eth","following":false}
GET /v1/follow/cto.geocities.eth/counts
200 {"name":"cto.geocities.eth","followers":12,"following":3}
Errors:
| Status | error | When |
|---|---|---|
| 400 | cannot_follow_self | Following or unfollowing your own name |
| 400 | invalid_name (+ detail) | Not <label>.geocities.eth or <tag>.<label>.geocities.eth |
| 400 | invalid_request | target is missing or not a string, or limit/cursor is bad |
| 401 | unauthorized | No session (follow, unfollow, is-following) |
| 404 | not_found | Well-formed but unknown name |
| 429 | rate_limited | Too many requests |
| – | (no error) | A duplicate follow is not an error. It returns 200 with "created": false. Unfollowing a name you don't follow returns 200 with "removed": false |