Misc
Retention analysis and user journey tracking endpoints
See the API Reference for authentication, common parameters, and filters.
Endpoints
Get Retention
GET /api/retention/:siteReturns cohort-based retention analysis data. Users are grouped into cohorts based on their first visit, and retention is tracked over subsequent time periods.
Path Parameters
Prop
Type
Query Parameters
Prop
Type
Response
Prop
Type
RetentionData Object
Prop
Type
CohortData Object
Prop
Type
curl -X GET "https://api.rybbit.io/api/retention/123?mode=week&range=90" \
-H "Authorization: Bearer your_api_key_here"const response = await fetch(
'https://api.rybbit.io/api/retention/123?mode=week&range=90',
{
headers: {
'Authorization': 'Bearer your_api_key_here'
}
}
);
const data = await response.json();import requests
response = requests.get(
'https://api.rybbit.io/api/retention/123',
params={
'mode': 'week',
'range': 90
},
headers={
'Authorization': 'Bearer your_api_key_here'
}
)
data = response.json()$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://api.rybbit.io/api/retention/123?mode=week&range=90');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: Bearer your_api_key_here'
]);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);require 'net/http'
require 'json'
uri = URI('https://api.rybbit.io/api/retention/123?mode=week&range=90')
req = Net::HTTP::Get.new(uri)
req['Authorization'] = 'Bearer your_api_key_here'
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
data = JSON.parse(res.body)req, _ := http.NewRequest("GET", "https://api.rybbit.io/api/retention/123?mode=week&range=90", nil)
req.Header.Set("Authorization", "Bearer your_api_key_here")
client := &http.Client{}
resp, _ := client.Do(req)
defer resp.Body.Close()
var data map[string]interface{}
json.NewDecoder(resp.Body).Decode(&data)let client = reqwest::Client::new();
let res = client
.get("https://api.rybbit.io/api/retention/123?mode=week&range=90")
.header("Authorization", "Bearer your_api_key_here")
.send()
.await?;
let data: serde_json::Value = res.json().await?;HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.rybbit.io/api/retention/123?mode=week&range=90"))
.header("Authorization", "Bearer your_api_key_here")
.GET()
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());using var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", "Bearer your_api_key_here");
var response = await client.GetAsync("https://api.rybbit.io/api/retention/123?mode=week&range=90");
var data = await response.Content.ReadAsStringAsync();{
"data": {
"cohorts": {
"2024-01-01": {
"size": 1250,
"percentages": [100, 45.2, 32.1, 28.5, 25.3, 22.1]
},
"2024-01-08": {
"size": 1420,
"percentages": [100, 48.5, 35.2, 30.1, 26.8, null]
},
"2024-01-15": {
"size": 1380,
"percentages": [100, 46.8, 33.5, 29.2, null, null]
},
"2024-01-22": {
"size": 1510,
"percentages": [100, 44.2, 31.8, null, null, null]
},
"2024-01-29": {
"size": 1290,
"percentages": [100, 47.1, null, null, null, null]
}
},
"maxPeriods": 5,
"mode": "week",
"range": 90
}
}Understanding Retention Data
The retention data shows how many users from each cohort return in subsequent periods:
- Period 0: Always 100% (the cohort's first visit)
- Period 1: Users who returned 1 week later
- Period 2: Users who returned 2 weeks later
- etc.
A null value indicates that period hasn't occurred yet for that cohort.
Visualization Example
const { cohorts, maxPeriods } = data.data;
// Headers: Cohort, Size, Week 0, Week 1, Week 2, ...
const headers = ['Cohort', 'Size',
...Array(maxPeriods + 1).fill(0).map((_, i) => `Week ${i}`)
];
// Rows
Object.entries(cohorts).forEach(([date, cohort]) => {
const row = [
date,
cohort.size,
...cohort.percentages.map(p => p !== null ? `${p}%` : '-')
];
console.log(row.join(' | '));
});Get Journeys
GET /api/journeys/:siteReturns the most common page navigation paths (user journeys) within sessions. Useful for understanding how users navigate through your site.
Path Parameters
Prop
Type
Query Parameters
Accepts all Common Parameters plus the following:
Prop
Type
Response
Prop
Type
Journey Object
Prop
Type
curl -X GET "https://api.rybbit.io/api/journeys/123?steps=4&limit=20&start_date=2024-01-01&end_date=2024-01-31" \
-H "Authorization: Bearer your_api_key_here"const response = await fetch(
'https://api.rybbit.io/api/journeys/123?steps=4&limit=20&start_date=2024-01-01&end_date=2024-01-31',
{
headers: {
'Authorization': 'Bearer your_api_key_here'
}
}
);
const data = await response.json();import requests
response = requests.get(
'https://api.rybbit.io/api/journeys/123',
params={
'steps': 4,
'limit': 20,
'start_date': '2024-01-01',
'end_date': '2024-01-31'
},
headers={
'Authorization': 'Bearer your_api_key_here'
}
)
data = response.json()$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://api.rybbit.io/api/journeys/123?steps=4&limit=20&start_date=2024-01-01&end_date=2024-01-31');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: Bearer your_api_key_here'
]);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);require 'net/http'
require 'json'
uri = URI('https://api.rybbit.io/api/journeys/123?steps=4&limit=20&start_date=2024-01-01&end_date=2024-01-31')
req = Net::HTTP::Get.new(uri)
req['Authorization'] = 'Bearer your_api_key_here'
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
data = JSON.parse(res.body)req, _ := http.NewRequest("GET", "https://api.rybbit.io/api/journeys/123?steps=4&limit=20&start_date=2024-01-01&end_date=2024-01-31", nil)
req.Header.Set("Authorization", "Bearer your_api_key_here")
client := &http.Client{}
resp, _ := client.Do(req)
defer resp.Body.Close()
var data map[string]interface{}
json.NewDecoder(resp.Body).Decode(&data)let client = reqwest::Client::new();
let res = client
.get("https://api.rybbit.io/api/journeys/123?steps=4&limit=20&start_date=2024-01-01&end_date=2024-01-31")
.header("Authorization", "Bearer your_api_key_here")
.send()
.await?;
let data: serde_json::Value = res.json().await?;HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.rybbit.io/api/journeys/123?steps=4&limit=20&start_date=2024-01-01&end_date=2024-01-31"))
.header("Authorization", "Bearer your_api_key_here")
.GET()
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());using var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", "Bearer your_api_key_here");
var response = await client.GetAsync("https://api.rybbit.io/api/journeys/123?steps=4&limit=20&start_date=2024-01-01&end_date=2024-01-31");
var data = await response.Content.ReadAsStringAsync();{
"journeys": [
{
"path": ["/", "/pricing", "/signup"],
"count": 1250,
"percentage": 8.12
},
{
"path": ["/", "/features", "/pricing", "/signup"],
"count": 890,
"percentage": 5.78
},
{
"path": ["/blog/getting-started", "/", "/pricing"],
"count": 650,
"percentage": 4.22
},
{
"path": ["/", "/docs", "/docs/quickstart"],
"count": 580,
"percentage": 3.77
},
{
"path": ["/", "/about", "/contact"],
"count": 420,
"percentage": 2.73
}
]
}Filtering by Step
You can filter journeys that include specific pages at specific steps:
curl -X GET "https://api.rybbit.io/api/journeys/123?steps=3&stepFilters=%7B%220%22%3A%22%2F%22%7D" \
-H "Authorization: Bearer your_api_key_here"const stepFilters = JSON.stringify({ "0": "/" });
const response = await fetch(
`https://api.rybbit.io/api/journeys/123?steps=3&stepFilters=${encodeURIComponent(stepFilters)}`,
{
headers: {
'Authorization': 'Bearer your_api_key_here'
}
}
);import requests
response = requests.get(
'https://api.rybbit.io/api/journeys/123?steps=3&stepFilters=%7B%220%22%3A%22%2F%22%7D',
headers={
'Authorization': 'Bearer your_api_key_here'
}
)
data = response.json()$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, 'https://api.rybbit.io/api/journeys/123?steps=3&stepFilters=%7B%220%22%3A%22%2F%22%7D');
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_HTTPHEADER, [
'Authorization: Bearer your_api_key_here'
]);
$response = curl_exec($ch);
curl_close($ch);
$data = json_decode($response, true);require 'net/http'
require 'json'
uri = URI('https://api.rybbit.io/api/journeys/123?steps=3&stepFilters=%7B%220%22%3A%22%2F%22%7D')
req = Net::HTTP::Get.new(uri)
req['Authorization'] = 'Bearer your_api_key_here'
res = Net::HTTP.start(uri.hostname, uri.port, use_ssl: true) { |http| http.request(req) }
data = JSON.parse(res.body)req, _ := http.NewRequest("GET", "https://api.rybbit.io/api/journeys/123?steps=3&stepFilters=%7B%220%22%3A%22%2F%22%7D", nil)
req.Header.Set("Authorization", "Bearer your_api_key_here")
client := &http.Client{}
resp, _ := client.Do(req)
defer resp.Body.Close()
var data map[string]interface{}
json.NewDecoder(resp.Body).Decode(&data)let client = reqwest::Client::new();
let res = client
.get("https://api.rybbit.io/api/journeys/123?steps=3&stepFilters=%7B%220%22%3A%22%2F%22%7D")
.header("Authorization", "Bearer your_api_key_here")
.send()
.await?;
let data: serde_json::Value = res.json().await?;HttpClient client = HttpClient.newHttpClient();
HttpRequest request = HttpRequest.newBuilder()
.uri(URI.create("https://api.rybbit.io/api/journeys/123?steps=3&stepFilters=%7B%220%22%3A%22%2F%22%7D"))
.header("Authorization", "Bearer your_api_key_here")
.GET()
.build();
HttpResponse<String> response = client.send(request, HttpResponse.BodyHandlers.ofString());using var client = new HttpClient();
client.DefaultRequestHeaders.Add("Authorization", "Bearer your_api_key_here");
var response = await client.GetAsync("https://api.rybbit.io/api/journeys/123?steps=3&stepFilters=%7B%220%22%3A%22%2F%22%7D");
var data = await response.Content.ReadAsStringAsync();{
"journeys": [
{
"path": ["/", "/pricing", "/signup"],
"count": 1250,
"percentage": 12.5
},
{
"path": ["/", "/features", "/pricing"],
"count": 890,
"percentage": 8.9
},
{
"path": ["/", "/docs", "/docs/quickstart"],
"count": 580,
"percentage": 5.8
}
]
}