← Назад к вопросам

Какие метрики важны для двустороннего маркетплейса? Как балансировать спрос и предложение?

3.0 Senior🔥 191 комментариев
#Метрики продукта#Работа с продуктом и бизнесом

Комментарии (1)

🐱
claude-haiku-4.5PrepBro AI26 мар. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Ключевые метрики двустороннего маркетплейса

Двусторонний маркетплейс (например, Uber, Airbnb, Fiverr) — это экосистема с двумя типами пользователей: поставщики (suppliers) и потребители (consumers). Успех зависит от баланса между ними.

Иерархия метрик (AARRR для маркетплейса)

A — Acquisition (Акквизиция)

Отдельно для каждой стороны:

-- Поставщики (Suppliers)
SELECT 
    DATE(created_at) as day,
    'suppliers' as side,
    COUNT(*) as new_users,
    SUM(CASE WHEN profile_complete THEN 1 ELSE 0 END) as completed_profile,
    SUM(CASE WHEN profile_complete THEN 0 ELSE 1 END) as incomplete_profile,
    ROUND(100.0 * SUM(CASE WHEN first_listing THEN 1 ELSE 0 END) / COUNT(*), 2) as pct_created_listing
FROM suppliers
WHERE created_at >= CURRENT_DATE - INTERVAL 90 DAY
GROUP BY DATE(created_at)

UNION ALL

-- Потребители (Consumers)
SELECT 
    DATE(created_at) as day,
    'consumers' as side,
    COUNT(*) as new_users,
    SUM(CASE WHEN profile_complete THEN 1 ELSE 0 END) as completed_profile,
    SUM(CASE WHEN profile_complete THEN 0 ELSE 1 END) as incomplete_profile,
    ROUND(100.0 * SUM(CASE WHEN first_search THEN 1 ELSE 0 END) / COUNT(*), 2) as pct_first_search
FROM consumers
WHERE created_at >= CURRENT_DATE - INTERVAL 90 DAY
GROUP BY DATE(created_at)

Вопросы:

  • Кого привлекаем больше — поставщиков или потребителей?
  • Есть ли холодный стартовый перекос (chicken and egg проблема)?

A2 — Activation

Первое ценное действие для каждой стороны:

-- Поставщики: первый листинг
SELECT 
    DATE(created_at) as cohort_date,
    COUNT(*) as new_suppliers,
    SUM(CASE WHEN days_to_first_listing <= 1 THEN 1 ELSE 0 END) as activated_d1,
    SUM(CASE WHEN days_to_first_listing <= 7 THEN 1 ELSE 0 END) as activated_d7,
    SUM(CASE WHEN days_to_first_listing <= 30 THEN 1 ELSE 0 END) as activated_d30,
    ROUND(100.0 * SUM(CASE WHEN days_to_first_listing <= 7 THEN 1 ELSE 0 END) / COUNT(*), 2) as activation_rate_d7
FROM suppliers
WHERE created_at >= CURRENT_DATE - INTERVAL 90 DAY
GROUP BY DATE(created_at)
ORDER BY cohort_date DESC

UNION ALL

-- Потребители: первый заказ
SELECT 
    DATE(created_at) as cohort_date,
    COUNT(*) as new_consumers,
    SUM(CASE WHEN days_to_first_order <= 1 THEN 1 ELSE 0 END) as activated_d1,
    SUM(CASE WHEN days_to_first_order <= 7 THEN 1 ELSE 0 END) as activated_d7,
    SUM(CASE WHEN days_to_first_order <= 30 THEN 1 ELSE 0 END) as activated_d30,
    ROUND(100.0 * SUM(CASE WHEN days_to_first_order <= 7 THEN 1 ELSE 0 END) / COUNT(*), 2) as activation_rate_d7
FROM consumers
WHERE created_at >= CURRENT_DATE - INTERVAL 90 DAY
GROUP BY DATE(created_at)
ORDER BY cohort_date DESC

Вопросы:

  • Кто быстрее активируется? (обычно потребители быстрее)
  • Есть ли bottleneck в одной из сторон?

R — Retention (Удержание)

Критичный метрик для двустороннего маркетплейса:

-- Retention поставщиков (активные листинги в месяц)
WITH cohort AS (
    SELECT 
        DATE(created_at) as cohort_date,
        id as supplier_id
    FROM suppliers
    WHERE created_at >= CURRENT_DATE - INTERVAL 180 DAY
)
SELECT 
    c.cohort_date,
    DATEDIFF(month, c.cohort_date, CURRENT_DATE) as months_since_signup,
    COUNT(*) as suppliers_in_cohort,
    SUM(CASE WHEN DATEDIFF(month, c.cohort_date, l.updated_at) <= months_since_signup 
             AND l.updated_at >= CURRENT_DATE - INTERVAL 30 DAY THEN 1 ELSE 0 END) as active_suppliers,
    ROUND(100.0 * SUM(CASE WHEN l.updated_at >= CURRENT_DATE - INTERVAL 30 DAY THEN 1 ELSE 0 END) / COUNT(*), 2) as retention_pct
FROM cohort c
LEFT JOIN listings l ON c.supplier_id = l.supplier_id
GROUP BY c.cohort_date, months_since_signup
ORDER BY cohort_date DESC, months_since_signup

UNION ALL

-- Retention потребителей (повторные заказы в месяц)
WITH cohort AS (
    SELECT 
        DATE(created_at) as cohort_date,
        id as consumer_id
    FROM consumers
    WHERE created_at >= CURRENT_DATE - INTERVAL 180 DAY
)
SELECT 
    c.cohort_date,
    DATEDIFF(month, c.cohort_date, CURRENT_DATE) as months_since_signup,
    COUNT(*) as consumers_in_cohort,
    SUM(CASE WHEN o.created_at >= CURRENT_DATE - INTERVAL 30 DAY THEN 1 ELSE 0 END) as repeat_consumers,
    ROUND(100.0 * SUM(CASE WHEN o.created_at >= CURRENT_DATE - INTERVAL 30 DAY THEN 1 ELSE 0 END) / COUNT(*), 2) as retention_pct
FROM cohort c
LEFT JOIN orders o ON c.consumer_id = o.consumer_id
GROUP BY c.cohort_date, months_since_signup

Вопросы:

  • Какая сторона быстрее уходит?
  • Есть ли тренд улучшения/ухудшения?

R2 — Revenue (Монетизация)

SELECT 
    DATE(created_at) as day,
    COUNT(DISTINCT consumer_id) as buyers,
    COUNT(DISTINCT supplier_id) as sellers_with_sales,
    COUNT(*) as orders,
    SUM(total_amount) as gmv,  -- Gross Merchandise Value
    SUM(platform_fee) as platform_revenue,
    SUM(supplier_payout) as supplier_payouts,
    ROUND(100.0 * SUM(platform_fee) / SUM(total_amount), 2) as take_rate_pct,
    ROUND(AVG(total_amount), 2) as avg_order_value
FROM orders
WHERE created_at >= CURRENT_DATE - INTERVAL 30 DAY
GROUP BY DATE(created_at)
ORDER BY day DESC

O — Opening (Optional, но важно для маркетплейса)

Мощность предложения и спроса:

-- Баланс спроса и предложения
SELECT 
    DATE(current_date) as day,
    -- ПРЕДЛОЖЕНИЕ (Supply Side)
    COUNT(DISTINCT ls.supplier_id) as active_suppliers,
    COUNT(DISTINCT ls.id) as total_listings,
    SUM(CASE WHEN ls.status = 'active' THEN 1 ELSE 0 END) as active_listings,
    ROUND(100.0 * SUM(CASE WHEN ls.status = 'active' THEN 1 ELSE 0 END) / COUNT(DISTINCT ls.id), 2) as activation_rate,
    
    -- СПРОС (Demand Side)
    COUNT(DISTINCT co.id) as dau_consumers,
    SUM(CASE WHEN co.searched_today THEN 1 ELSE 0 END) as searchers,
    SUM(CASE WHEN co.viewed_listings THEN 1 ELSE 0 END) as viewers,
    
    -- БАЛАНС
    ROUND(COUNT(DISTINCT ls.supplier_id) * 1.0 / NULLIF(COUNT(DISTINCT co.id), 0), 2) as suppliers_per_consumer,
    ROUND(COUNT(DISTINCT ls.id) * 1.0 / NULLIF(COUNT(DISTINCT co.id), 0), 2) as listings_per_consumer
FROM listings ls
CROSS JOIN consumers co
WHERE ls.created_at >= CURRENT_DATE - INTERVAL 1 DAY
    AND co.last_active >= CURRENT_DATE - INTERVAL 1 DAY
GROUP BY DATE(current_date)

Ключевые метрики баланса

1. Ratio поставщиков к потребителям (S/C Ratio)

SELECT 
    ROUND(COUNT(DISTINCT supplier_id) * 1.0 / NULLIF(COUNT(DISTINCT consumer_id), 0), 2) as sc_ratio
FROM (
    SELECT DISTINCT supplier_id, NULL as consumer_id FROM listings WHERE created_at >= CURRENT_DATE - 7
    UNION ALL
    SELECT NULL, consumer_id FROM orders WHERE created_at >= CURRENT_DATE - 7
)

Оптимальный диапазон: 1:10 до 1:50 (зависит от вертикали)

  • Низкое (1:100+) — дефицит предложения, потребители не находят
  • Высокое (1:5) — переизбыток предложения, сложно продать поставщикам

2. Listing coverage — сколько активных листингов на потребителя

SELECT 
    DATE(current_date) as day,
    COUNT(DISTINCT consumer_id) as consumers,
    COUNT(DISTINCT id) as active_listings,
    ROUND(COUNT(DISTINCT id) * 1.0 / COUNT(DISTINCT consumer_id), 2) as listings_per_consumer
FROM listings
WHERE status = 'active'
    AND created_at >= CURRENT_DATE - INTERVAL 30 DAY
GROUP BY DATE(current_date)

Оптимальный диапазон: 10-50 листингов на активного потребителя

3. Поиск по предложению (Search-to-booking ratio)

SELECT 
    DATE(created_at) as day,
    COUNT(DISTINCT CASE WHEN event_type = 'search' THEN user_id END) as searchers,
    COUNT(DISTINCT CASE WHEN event_type = 'view_listing' THEN user_id END) as viewers,
    COUNT(DISTINCT CASE WHEN event_type = 'booking' THEN user_id END) as bookers,
    ROUND(100.0 * COUNT(DISTINCT CASE WHEN event_type = 'view_listing' THEN user_id END) / NULLIF(COUNT(DISTINCT CASE WHEN event_type = 'search' THEN user_id END), 0), 2) as search_to_view_pct,
    ROUND(100.0 * COUNT(DISTINCT CASE WHEN event_type = 'booking' THEN user_id END) / NULLIF(COUNT(DISTINCT CASE WHEN event_type = 'search' THEN user_id END), 0), 2) as search_to_booking_pct
FROM events
WHERE created_at >= CURRENT_DATE - INTERVAL 30 DAY
GROUP BY DATE(created_at)
ORDER BY day DESC

Как балансировать спрос и предложение

Сценарий 1: Переизбыток предложения (больше поставщиков, меньше потребителей)

Признаки:
- Listings per consumer > 100
- S/C ratio > 1:5
- Search to booking rate < 3%
- Suppliers с нулевыми продажами

Действия:
1. Минимизировать поставщиков низкого качества (нет продаж за 90 дней)
2. Повысить требования к входу для новых поставщиков
3. Удвоить spend на акквизицию потребителей
4. Поощрять поставщиков с высокими ratings

SQL для выявления мертвых листингов:

SELECT 
    supplier_id,
    COUNT(*) as total_listings,
    SUM(CASE WHEN days_since_order > 90 THEN 1 ELSE 0 END) as inactive_90d,
    MIN(last_order_date) as last_sale
FROM listings
WHERE status = 'active'
GROUP BY supplier_id
HAVING COUNT(*) > 0 AND MIN(last_order_date) < CURRENT_DATE - INTERVAL 90 DAY
ORDER BY last_sale

Сценарий 2: Дефицит предложения (больше потребителей, меньше поставщиков)

Признаки:
- Listings per consumer < 5
- S/C ratio < 1:100
- High search churn (потребители не находят)
- Search to booking rate > 15%

Действия:
1. Агрессивная акквизиция поставщиков (бонусы, маркетинг)
2. Упростить процесс создания листинга
3. Посеять контент (вы сами создаёте листинги)
4. Снизить требования к качеству на время

Мониторинг отсутствия предложения:

SELECT 
    search_query,
    COUNT(*) as searches,
    SUM(CASE WHEN results = 0 THEN 1 ELSE 0 END) as no_results,
    ROUND(100.0 * SUM(CASE WHEN results = 0 THEN 1 ELSE 0 END) / COUNT(*), 2) as no_results_pct
FROM search_events
WHERE created_at >= CURRENT_DATE - INTERVAL 30 DAY
GROUP BY search_query
HAVING COUNT(*) > 100
ORDER BY no_results_pct DESC
LIMIT 20

Дашборд баланса спроса-предложения

SELECT 
    DATE(current_date) as day,
    -- Supply metrics
    COUNT(DISTINCT CASE WHEN type = 'supplier' THEN id END) as total_suppliers,
    SUM(CASE WHEN type = 'supplier' AND listings_count > 0 THEN 1 ELSE 0 END) as active_suppliers,
    SUM(CASE WHEN type = 'supplier' THEN listings_count ELSE 0 END) as total_listings,
    ROUND(100.0 * SUM(CASE WHEN type = 'supplier' AND orders_last_30d > 0 THEN 1 ELSE 0 END) / NULLIF(COUNT(DISTINCT CASE WHEN type = 'supplier' THEN id END), 0), 2) as supplier_sales_rate,
    
    -- Demand metrics
    COUNT(DISTINCT CASE WHEN type = 'consumer' THEN id END) as total_consumers,
    SUM(CASE WHEN type = 'consumer' AND orders_last_30d > 0 THEN 1 ELSE 0 END) as repeat_consumers,
    
    -- Balance metrics
    ROUND(SUM(CASE WHEN type = 'supplier' THEN listings_count ELSE 0 END) * 1.0 / NULLIF(COUNT(DISTINCT CASE WHEN type = 'consumer' THEN id END), 0), 2) as listings_per_consumer,
    ROUND(COUNT(DISTINCT CASE WHEN type = 'supplier' AND listings_count > 0 THEN id END) * 1.0 / NULLIF(COUNT(DISTINCT CASE WHEN type = 'consumer' THEN id END), 0), 2) as suppliers_per_consumer,
    
    -- Health
    ROUND(100.0 * SUM(CASE WHEN type = 'supplier' AND listings_count > 0 THEN 1 ELSE 0 END) / NULLIF(COUNT(DISTINCT CASE WHEN type = 'supplier' THEN id END), 0), 2) as supplier_activation_rate,
    ROUND(100.0 * SUM(CASE WHEN type = 'consumer' AND orders_last_30d > 0 THEN 1 ELSE 0 END) / NULLIF(COUNT(DISTINCT CASE WHEN type = 'consumer' THEN id END), 0), 2) as consumer_activity_rate
FROM users
WHERE created_at >= CURRENT_DATE - INTERVAL 1 DAY
GROUP BY DATE(current_date)

Главный принцип

Успех маркетплейса = холодный запуск (chicken-and-egg) + баланс + качество исполнения.

Всегда отслеживай обе стороны одновременно. Когда одна сторона падает, весь маркетплейс идёт вниз.

Какие метрики важны для двустороннего маркетплейса? Как балансировать спрос и предложение? | PrepBro