TypeScript/JavaScript client for the Open Measures API, providing access to social media data from alternative platforms for research and analysis.
npm install open-measuresimport { OpenMeasuresClient, Site, QueryType } from 'open-measures';
// Public API (rate limited, 6-month delayed data)
const client = new OpenMeasuresClient();
// Pro API with authentication
const proClient = new OpenMeasuresClient({
apiKey: process.env.OPEN_MEASURES_API_KEY,
});
// Search for content
const results = await client.content({
term: 'climate change',
site: Site.TELEGRAM,
limit: 100,
});
console.log(`Found ${results.total_hits} results`);
for (const hit of results.results) {
console.log(hit._source.text);
}const client = new OpenMeasuresClient({
// JWT token for Pro API access (optional for public API)
apiKey: 'your-api-key',
// Custom base URL (optional)
baseUrl: 'https://pro.api.openmeasures.io',
// Request timeout in ms (default: 30000)
timeout: 60000,
});Search for posts, comments, and messages across platforms.
const results = await client.content({
term: 'search query',
site: Site.TELEGRAM, // or array: [Site.TELEGRAM, Site.GAB]
querytype: QueryType.BOOLEAN_CONTENT,
standard_fields: true, // Use standardized field names
since: '2024-01-01', // ISO 8601 date or Date object
until: '2024-06-01',
limit: 100, // Max 10000 (1000 with media)
returnmedia: false, // Include media URLs
returnthumbnails: false, // Include thumbnail URLs
});
// Iterate through results
for (const hit of results.results) {
console.log(hit._source.text);
console.log(hit._source.actor?.username);
console.log(hit._source.created_at);
}
// Paginate with search_after
const page2 = await client.content({
term: 'search query',
site: Site.TELEGRAM,
search_after: results.search_after,
});Automatically paginate through all results:
for await (const hit of client.contentIterator({
term: 'example',
site: Site.TELEGRAM,
limit: 1000,
})) {
console.log(hit._source.text);
}Get aggregated counts over time for trend analysis:
const timeseries = await client.timeseries({
term: 'bitcoin',
site: Site.TELEGRAM,
interval: Interval.DAY, // HOUR, DAY, WEEK, MONTH, QUARTER, YEAR
since: '2024-01-01',
changepoint: true, // Enable changepoint detection
});
for (const bucket of timeseries.aggregations.over_time?.buckets ?? []) {
console.log(`${bucket.key_as_string}: ${bucket.doc_count}`);
}Aggregate content by field to find top users, channels, etc.:
const activity = await client.activity({
term: 'news',
site: Site.TELEGRAM,
agg_by: 'context.username', // Field to aggregate
aggregation_size: 20, // Number of buckets (max 100)
});
for (const bucket of activity.aggregations.agg?.buckets ?? []) {
console.log(`${bucket.key}: ${bucket.doc_count} posts`);
}Find user profiles, channels, and groups:
const actors = await client.actors({
term: 'news',
site: ActorSite.TELEGRAM_CHANNEL,
fullsearch: false, // Enable Lucene query string
limit: 50,
});
for (const actor of actors.results) {
console.log(actor.username, actor.stats?.followers);
}Get downloadable URLs for media content:
const media = await client.media({
media_hash: 'abc123...',
site: Site.TELEGRAM,
media_type: MediaType.MEDIA, // or MediaType.THUMBNAIL
});
console.log(media.openmeasures_media_url);const quota = await client.quota();
console.log(quota);Manage monitoring requests for keywords, profiles, and channels:
// Get existing crawl requests
const crawls = await client.getCrawlRequests({
crawl_type: CrawlRequestType.KEYWORD,
limit: 100,
});
// Create a new crawl request
await client.createCrawlRequest({
crawl_type: 'keyword',
keyword: 'election',
source: 'telegram',
});
// Update a crawl request
await client.updateCrawlRequest({
crawl_type: CrawlRequestType.KEYWORD,
crawl_id: 'crawl-id',
crawl_status: false, // Disable crawling
});Generate search queries from natural language:
const generated = await client.queryGenerate({
user_message: 'Find posts about election fraud',
service: 'claude',
});
console.log(generated.generated_query);
// Augment existing query
const augmented = await client.queryAugment({
query: 'election fraud',
instruction: 'Add terms for ballot tampering',
service: 'claude',
});
console.log(augmented.augmented_query);4chan,8kunbitchute_comment,bitchute_videoblueskydiscorddisqusfediversegabgettrkiwifarmslbry_comment,lbry_videomewe,mewe_chatmindsokparlerpoalrumble_comment,rumble_videorutube_comment,rutube_videotelegramtiktok_comment,tiktok_videotruthsocialvkwhatsappwin- And more...
telegram_channel,telegram_usergab_user,gab_groupbluesky_userdiscord_channel,discord_user- And more...
boolean_content: Boolean logic search over primary text fieldquery_string: Elasticsearch query string syntax for advanced searches
import { OpenMeasuresError } from 'open-measures';
try {
const results = await client.content({ term: 'test' });
} catch (error) {
if (error instanceof OpenMeasuresError) {
console.error(`API Error: ${error.message}`);
console.error(`Status: ${error.statusCode}`);
console.error(`Response: ${JSON.stringify(error.response)}`);
}
}Full TypeScript support with exported types:
import type {
ContentParams,
ContentResponse,
StandardSchema,
ActorSchema,
Site,
} from 'open-measures';MIT