Walk through the social and user data endpoints to build a simple trader leaderboard using the eToro API.
Social trading blends market data with people data: who is posting, how they have performed, and what the community is discussing. This guide tours the Social Feeds and Users Info surfaces of the eToro API, then stitches them into a minimal leaderboard that ranks traders by a published performance metric.
All REST examples use https://public-api.etoro.com/api/v1/ and send x-api-key, optional x-user-key when acting as a logged-in user, and a unique x-request-id per call.
Start with a known user ID or username from the portal or your app. A profile GET returns display name, avatar URL, bio, and flags such as whether the user is a Popular Investor.
curl -sS "https://public-api.etoro.com/api/v1/users/12345678/info" \
-H "x-api-key: $ETORO_API_KEY" \
-H "x-request-id: $(uuidgen)" \
-H "accept: application/json"
The same call in JavaScript is useful when you are assembling leaderboard rows in a serverless function or Node script.
import { randomUUID } from "node:crypto";
const BASE = "https://public-api.etoro.com/api/v1";
async function fetchProfile(userId) {
const res = await fetch(`${BASE}/users/${userId}/info`, {
headers: {
"x-api-key": process.env.ETORO_API_KEY,
"x-user-key": process.env.ETORO_USER_KEY ?? "",
"x-request-id": randomUUID(),
accept: "application/json",
},
});
if (!res.ok) throw new Error(`profile ${userId}: ${res.status}`);
const { data } = await res.json();
return data;
}
Leaderboards need numbers. Call a performance endpoint that returns time-windowed returns, risk score, and max drawdown. Cache aggressively—many consumers poll too often; respect rate limits and ETag headers if provided.
async function fetchPerformance(userId) {
const res = await fetch(
`${BASE}/users/${userId}/performance?window=12m`,
{
headers: {
"x-api-key": process.env.ETORO_API_KEY,
"x-user-key": process.env.ETORO_USER_KEY ?? "",
"x-request-id": randomUUID(),
},
}
);
if (!res.ok) throw new Error(`performance ${userId}: ${res.status}`);
const { data } = await res.json();
return {
returnPct: data.returnPercent,
risk: data.riskScore,
copiers: data.activeCopiers,
};
}
Social feeds provide qualitative context—posts, instruments mentioned, and engagement. Use cursor parameters for pagination and stop when the API returns an empty nextCursor.
curl -sS "https://public-api.etoro.com/api/v1/feeds/instruments/100000?limit=20" \
-H "x-api-key: $ETORO_API_KEY" \
-H "x-user-key: $ETORO_USER_KEY" \
-H "x-request-id: $(uuidgen)"
In JavaScript, map feed items to { userId, text, instruments } and join against the profile and performance helpers above if you want a “signal strength” panel next to raw posts.
async function fetchFeedPage(instrumentId, cursor) {
const qs = new URLSearchParams({ limit: "20" });
if (cursor) qs.set("cursor", cursor);
const res = await fetch(`${BASE}/feeds/instruments/${instrumentId}?${qs}`, {
headers: {
"x-api-key": process.env.ETORO_API_KEY,
"x-user-key": process.env.ETORO_USER_KEY,
"x-request-id": randomUUID(),
},
});
if (!res.ok) throw new Error(`feed: ${res.status}`);
return res.json();
}
Given an array of candidate user IDs (for example Popular Investors you care about), fetch performance for each, sort by returnPct descending, and attach profile names for display. Use Promise.all with modest concurrency (e.g. p-limit or a manual chunk size) to avoid bursting through rate limits.
async function buildLeaderboard(userIds) {
const rows = await Promise.all(
userIds.map(async (id) => {
const [profile, perf] = await Promise.all([
fetchProfile(id),
fetchPerformance(id),
]);
return {
id,
name: profile.displayName,
return12m: perf.returnPct,
risk: perf.risk,
copiers: perf.copiers,
};
})
);
return rows.sort((a, b) => b.return12m - a.return12m);
}
Production scripts should treat 429 Too Many Requests and 5xx responses as transient: sleep with jitter, respect Retry-After when present, and cap total attempts. For 404 on optional resources (for example a user who closed their public profile), degrade gracefully instead of failing the whole leaderboard job. Log the upstream x-request-id together with your own correlation id so support can match client logs to server traces.
When you batch profile and performance calls, prefer fixed concurrency (five to ten parallel requests is a reasonable starting point) over unbounded Promise.all across hundreds of IDs. That pattern keeps latency predictable and reduces the chance of tripping fair-use policies during spikes.
Social data can include personal information—store only what you need, honor opt-out and regional restrictions shown in the developer terms, and never present rankings as investment advice. When in doubt, display disclaimers and link to the trader’s full statistics in the eToro client.
From this foundation you can add copy-trading eligibility checks, filter by instrument, or combine feed sentiment with your own risk models—still using the same header and base-URL conventions throughout.
Was this helpful?
A step-by-step guide to building a simple trading bot using the eToro Demo Trading API.
How to programmatically search, filter, and explore eToro's instrument catalog — asset classes, exchanges, industries, and historical data.
Be the first to know when we publish new API guides, changelog entries, and developer resources.
Newsletter coming soon. We'll only email you when it launches.