Use SocQ to organize Twitter/X community names, descriptions, rules, and member and moderator counts in a profile table. Save the sources and capture times, then connect posts to the recorded community context for review.
The SocQ X Community API queries metadata by public community URL. This guide covers requests, returned fields, and JSON and CSV exports with source links and collection times.
Quick answer: Put
x.com/i/communities/{numeric_id}links inurlsand submit them toPOST /v1/x/community. After success, read names, descriptions, rules, member and moderator counts, and joining and invitation policies fromdata.results.items. Query posts separately with Community Posts.
Build a Profile Table from Community URLs
Put a community URL in urls to query its name, description, rules, member and moderator counts, and joining and invitation policies. This example uses the Build in Public community:
https://x.com/i/communities/1493446837214187523
The final numeric segment is the community ID. Supply the complete /i/communities/{numeric_id} URL in urls.
When starting with a name, find its community URL first. Match records by numeric community ID and keep communities with different IDs separate even when their names match.
| Question | Use |
|---|---|
| What metadata is available for this community? | X Community |
| Which posts can I collect from the community? | X Community Posts |
| How are the posts in one discussion related? | X Thread Context |
This endpoint queries topic-community metadata. Community Notes are annotations attached to posts and are a separate data type.
Request Community Details
Set SOCQ_API_KEY, then submit the URL:
curl -X POST "https://api.socq.ai/v1/x/community" \
-H "Authorization: Bearer $SOCQ_API_KEY" \
-H "Content-Type: application/json" \
-d '{"urls":["https://x.com/i/communities/1493446837214187523"]}'
For a batch, add public community links to urls. Each returned record describes one community; count results from the records actually returned.
Save data.task_id as TASK_ID, then query the existing task:
curl "https://api.socq.ai/v1/tasks/$TASK_ID?limit=100" \
-H "Authorization: Bearer $SOCQ_API_KEY"
Wait between checks while the status is queued, running or retrying. After succeeded, read data.results.items and any remaining stored result pages. If the task fails, inspect data.error_message. Task pagination reads saved data; it does not refresh community information.
Read Rules, Counts and Joining Policies
This metadata example shows selected fields and one rule from the rules array:
{
"id": "1493446837214187523",
"type": "community",
"name": "Build in Public",
"metrics": {"members_count": 268858, "moderators_count": 6},
"join_policy": "Open",
"invites_policy": "MemberInvitesAllowed",
"rules": [
{
"id": "1493447542045958144",
"name": "Share what you're working on",
"description": "Don't be scared to share unfinished work"
}
],
"collected_at": "2026-10-15T08:12:58.252843Z"
}
text stores the description, rules the structured rule list, and metrics the counts. Keep rule names and descriptions separate, with null for source-omitted descriptions.
metrics.members_count records the member total and metrics.moderators_count the moderator total. Save their collection times to compare counts for the same community across captures.
join_policy and invites_policy store the original joining and invitation policy strings. Keep the original when labeling a known value, and display unfamiliar values as returned. Verify actual joining access in X's current product interface.
Export a Community Profile Table with Python
Save this standard-library task helper as socq_collect.py:
import json
import os
import time
from urllib.parse import urlencode
from urllib.request import Request, urlopen
BASE = "https://api.socq.ai/v1"
PENDING = {"queued", "running", "retrying"}
def api(method, path, payload=None):
body = json.dumps(payload).encode("utf-8") if payload is not None else None
request = Request(
BASE + path, data=body, method=method,
headers={
"Authorization": "Bearer " + os.environ["SOCQ_API_KEY"],
"Content-Type": "application/json",
},
)
with urlopen(request, timeout=60) as response:
result = json.load(response)
if result.get("code") != 200:
raise RuntimeError(result)
return result["data"]
def collect(endpoint, payload):
task_id = api("POST", "/" + endpoint, payload)["task_id"]
print("Task:", task_id, flush=True)
path = "/tasks/" + task_id
deadline = time.monotonic() + 600
data = api("GET", path + "?limit=100")
while data["status"] in PENDING:
if time.monotonic() >= deadline:
raise TimeoutError("Resume GET " + path + "; do not resubmit automatically")
time.sleep(2)
data = api("GET", path + "?limit=100")
if data["status"] != "succeeded":
raise RuntimeError(data.get("error_message") or data["status"])
items, seen_cursors = [], set()
while True:
if time.monotonic() >= deadline:
raise TimeoutError("Resume pagination for " + task_id)
page = data["results"]
items.extend(page["items"])
if not page["has_more"]:
return task_id, items
cursor = page.get("next_cursor")
if not cursor or cursor in seen_cursors:
raise RuntimeError("Missing or repeated result cursor")
seen_cursors.add(cursor)
data = api("GET", path + "?" + urlencode({"limit": 100, "cursor": cursor}))
if data["status"] != "succeeded":
raise RuntimeError("Task is not ready for result pagination")
Save the exporter as export_communities.py in the same directory:
import csv
import json
from socq_collect import collect
urls = ["https://x.com/i/communities/1493446837214187523"]
task_id, items = collect("x/community", {"urls": urls})
with open("communities.json", "w", encoding="utf-8") as f:
json.dump({"task_id": task_id, "input": {"urls": urls}, "items": items},
f, ensure_ascii=False, indent=2)
fields = ["community_id", "url", "name", "description", "members_count",
"moderators_count", "join_policy", "invites_policy", "rules_json", "collected_at"]
def csv_cell(value):
if value is None:
return ""
if isinstance(value, str) and value.lstrip().startswith(("=", "+", "-", "@")):
return "'" + value
return value
with open("communities.csv", "w", encoding="utf-8-sig", newline="") as f:
writer = csv.DictWriter(f, fieldnames=fields)
writer.writeheader()
for item in items:
metrics = item.get("metrics") or {}
row = {"community_id": item.get("id"), "url": item.get("url"),
"name": item.get("name"), "description": item.get("text"),
"members_count": metrics.get("members_count"),
"moderators_count": metrics.get("moderators_count"),
"join_policy": item.get("join_policy"),
"invites_policy": item.get("invites_policy"),
"rules_json": json.dumps(item.get("rules"), ensure_ascii=False),
"collected_at": item.get("collected_at")}
writer.writerow({k: csv_cell(v) for k, v in row.items()})
python3 export_communities.py
The JSON retains the raw standard records and submitted links. The CSV provides one review row per returned community, with the rules serialized as JSON so commas and line breaks do not destroy their structure. rules_json=null remains distinguishable from an empty list. Formula-like public text is escaped only in CSV, and identifiers should be imported as text.
When an input returns no metadata, record the empty result and its query time separately. Keep previously saved metadata under its original collection time for historical comparison.
Connect Community Metadata to Collected Posts
Use the same confirmed community URL with X Community Posts when you need discussions. That starts a separate task and has a separate result cap. The community-posts tutorial shows how to preserve the input-community source while exporting posts.
Save community ID, source URL, task ID and collection time with the metadata. Attach the input community to each collected post so the profile and post tables can be joined by community ID.
Review the description, rules and collected posts together, with their respective capture times. For a post's reply relationships, continue with the thread-context tutorial.
Make Community Metadata a Reusable Research Resource
SocQ organizes community metadata into standard fields. Use the code to save a profile table and structured rules, then join collected posts by community ID. Descriptions, rules and discussions share an explicit source for research files, sample reviews and dated updates.
Open X Community and query your source URL.
FAQ
What does the Twitter Community API return?
Community names, descriptions, rules, member and moderator counts, joining policies and invitation policies. See the X Community API page for field definitions and billing.
How do I query metadata after the community migration announcement?
X published a Communities-to-XChat migration announcement. Use the target community URL for the metadata lookup: read returned records after task success, save the query time for empty results, and inspect error details on failure. Check joining and participation features in X's current interface.
Can I search for a community by name?
The lookup takes community URLs. Confirm the link associated with the name, then submit it in urls.
Does the member count include a list of members or moderators?
The response contains aggregate member and moderator counts. Individual account directories are separate data and are not part of this metadata response.
Does an Open policy mean I can join now?
Open is the joining-policy value returned in the metadata. Verify current joining access in X's interface; this endpoint reads the metadata.
Are community posts or Community Notes included?
Query community posts with X Community Posts. Community Notes are separate post annotations. This endpoint returns community metadata.
Can I use these counts to rank community activity?
Member and moderator totals describe scale. To study activity, collect posts, select a period using published_at in your application, and count posts, authors or interactions within that sample.
X API
Test the workflow with a public X URL
Submit public inputs and receive normalized records with traceable source context.
Explore X APIs