Перейти к основному содержимому

Конкурентный рентген — сравнение контента vs ТОП-3

Как объективно сравнить карточку клиента с тремя ближайшими конкурентами по 6 измерениям и превратить разрыв в конкретный план действий, который продаёт сам себя.

Проблема

Каждый продавец на Wildberries «знает» своих конкурентов. Проблема в том, что это знание субъективное и фрагментарное:

  • «У меня хорошие фото» — но у конкурента А их 14 штук, а у клиента 5. Это не «хорошие», это в 3 раза хуже
  • «Мы в ТОПе» — по 23 ключевым словам, а конкурент B в ТОП-50 по 87 ключам. Клиент теряет 73% органического трафика
  • «Рейтинг нормальный» — 4.2 при среднем 4.6 у ТОП-3. Каждая десятая доля рейтинга — это -5% конверсии
  • «Видео не нужно» — а у двух из трёх конкурентов видео есть, и их выручка в 3-6 раз больше

Без цифрового рентгена конкурентов продавец живёт в иллюзии. Он не видит конкретных gap-ов и не понимает, почему конкуренты продают больше. А когда не понимает причину — не готов платить за решение.

Почему именно ТОП-3, а не ТОП-10 или ТОП-20?

Три конкурента — это оптимум для продающего отчёта. ТОП-10 перегружает клиента данными, ТОП-1 выглядит недостижимым идеалом. ТОП-3 — это конкретные, ощутимые соперники в ценовом диапазоне клиента. Клиент видит: «Вот этот продавец продаёт в 4 раза больше меня, и у него 14 фото. У меня — 5. Понятно, что делать».

Пайплайн данных

Три эндпоинта MPStats — одна картина

flowchart LR
A["Клиент называет\nсвой SKU и категорию"] --> B["POST /wb/get/category\nТОП по выручке\nв ценовом диапазоне"]
B --> C["Выбор ТОП-3\nближайших по цене\nконкурентов"]
C --> D["GET /wb/get/item/{sku}/by_keywords\n× 4 SKU\n(клиент + 3 конкурента)"]
C --> E["Контент-метрики:\npicscount, hasvideo,\nhas3d, comments,\nrating, revenue, sales"]
D --> F["Сравнение по\n6 измерениям"]
E --> F
F --> G["PDF-отчёт\n20–30 страниц\nс gap-анализом"]

Используемые эндпоинты

ЭндпоинтКлючевые поляДля чего
POST /wb/get/categoryid, revenue, sales, final_price, picscount, hasvideo, has3d, comments, rating, category_positionПолучение ТОП товаров в категории для определения ТОП-3 конкурентов в ценовом диапазоне клиента
GET /wb/get/item/{sku}/by_keywordskeyword, position, frequencyСравнение SEO-видимости: по каким ключевым словам ранжируется каждый из 4 товаров и на каких позициях
Поля из categorypicscount, hasvideo, has3d, comments, rating, revenue, sales, final_priceПолный набор метрик для 6-мерного сравнения
Почему именно эти эндпоинты?

Связка category (определение конкурентов + метрики) + by_keywords (SEO-сравнение) покрывает все 6 измерений конкурентного анализа. Всего 5 API-вызовов (1 category + 4 by_keywords) — а на выходе полноценный конкурентный отчёт на 20-30 страниц.

Пайплайн шаг за шагом

  1. Определить категорию — клиент называет свой SKU, мы определяем категорию
  2. Получить ТОП по выручке — через POST /wb/get/category загружаем лидеров
  3. Выбрать ТОП-3 конкурентов — фильтруем по ценовому диапазону (±30% от цены клиента), берём 3 ближайших по выручке
  4. Загрузить ключевые слова — для всех 4 SKU (клиент + 3 конкурента) через by_keywords
  5. Сравнить по 6 измерениям — агрегация и gap-анализ
  6. Генерация PDF — брендированный отчёт с визуализациями

Анализ

Шаг 1. Получение данных и определение конкурентов

import httpx
from urllib.parse import quote

MPSTATS_TOKEN = "your_token"
BASE_URL = "https://mpstats.io/api"
HEADERS = {
"X-Mpstats-TOKEN": MPSTATS_TOKEN,
"Content-Type": "application/json",
}


def fetch_category_top(category: str, d1: str, d2: str, limit: int = 50) -> list:
"""Загружает ТОП товаров категории по выручке."""
resp = httpx.post(
f"{BASE_URL}/wb/get/category",
headers=HEADERS,
json={
"path": quote(category, safe=""),
"d1": d1,
"d2": d2,
"startRow": 0,
"endRow": limit,
"sortModel": [{"colId": "revenue", "sort": "desc"}],
},
timeout=30,
)
resp.raise_for_status()
return resp.json().get("data", [])


def find_top3_competitors(
products: list, client_sku: int, price_tolerance: float = 0.3
) -> tuple:
"""
Находит ТОП-3 конкурентов ближайших по ценовому диапазону.
Возвращает (client_product, [competitor_1, competitor_2, competitor_3]).
"""
client = next((p for p in products if p["id"] == client_sku), None)
if not client:
raise ValueError(f"SKU {client_sku} не найден в категории")

client_price = client["final_price"]
min_price = client_price * (1 - price_tolerance)
max_price = client_price * (1 + price_tolerance)

# Фильтруем по ценовому диапазону, исключаем клиента
competitors = [
p for p in products
if p["id"] != client_sku
and min_price <= p["final_price"] <= max_price
]

# Сортируем по выручке — берём ТОП-3
competitors.sort(key=lambda p: p["revenue"], reverse=True)
top3 = competitors[:3]

return client, top3


# --- Загрузка данных ---
category = "Электроника/Наушники"
products = fetch_category_top(category, "2025-01-01", "2025-01-31")

client_sku = 12345678
client, top3 = find_top3_competitors(products, client_sku)

print(f"Клиент: SKU {client['id']}, цена {client['final_price']} руб, "
f"выручка {client['revenue']:,.0f} руб")
print(f"\nТОП-3 конкурента:")
for i, comp in enumerate(top3, 1):
print(f" {i}. SKU {comp['id']}, цена {comp['final_price']} руб, "
f"выручка {comp['revenue']:,.0f} руб")

Шаг 2. Загрузка ключевых слов для SEO-сравнения

def fetch_keywords(sku: int) -> list:
"""Загружает ключевые слова и позиции для SKU."""
resp = httpx.get(
f"{BASE_URL}/wb/get/item/{sku}/by_keywords",
headers=HEADERS,
timeout=30,
)
if resp.status_code != 200:
return []
return resp.json()


# Собираем ключевые слова для всех 4 участников
all_skus = [client["id"]] + [c["id"] for c in top3]
keywords_data = {}

for sku in all_skus:
kw_list = fetch_keywords(sku)
keywords_data[sku] = kw_list
print(f"SKU {sku}: {len(kw_list)} ключевых слов")

Шаг 3. Шестимерное сравнение

Конкурентный рентген сравнивает клиента с каждым из ТОП-3 по 6 измерениям. Каждое измерение получает балл от 0 до 100.

def score_visual_content(product: dict) -> dict:
"""
Измерение 1: Визуальный контент.
Оценивает количество фото, наличие видео и 3D.
"""
photos = product.get("picscount", 0)
has_video = product.get("hasvideo", 0)
has_3d = product.get("has3d", 0)

# Балл: до 50 за фото (15 фото = 100%), до 30 за видео, до 20 за 3D
photo_score = min(photos / 15 * 50, 50)
video_score = 30 if has_video else 0
three_d_score = 20 if has_3d else 0

total = round(photo_score + video_score + three_d_score)

return {
"score": total,
"photos": photos,
"has_video": bool(has_video),
"has_3d": bool(has_3d),
}


def score_seo(keywords: list, top_n: int = 50) -> dict:
"""
Измерение 2: SEO-видимость.
Оценивает количество ключевых слов в ТОП-50.
"""
in_top = [kw for kw in keywords if kw.get("position", 999) <= top_n]
total_keywords = len(keywords)

# Нормализация: 100 ключей в ТОП-50 = 100 баллов
score = min(len(in_top) / 100 * 100, 100)

return {
"score": round(score),
"total_keywords": total_keywords,
"in_top50": len(in_top),
}


def score_social_proof(product: dict) -> dict:
"""
Измерение 3: Социальное доказательство.
Отзывы и рейтинг.
"""
comments = product.get("comments", 0)
rating = product.get("rating", 0)

# Балл: до 60 за отзывы (1000+ = макс), до 40 за рейтинг (4.8+ = макс)
comments_score = min(comments / 1000 * 60, 60)
rating_score = max(0, (rating - 3.0) / 2.0 * 40) # 3.0 = 0, 5.0 = 40

return {
"score": round(comments_score + rating_score),
"comments": comments,
"rating": rating,
}


def score_price_position(product: dict, all_products: list) -> dict:
"""
Измерение 4: Ценовое позиционирование.
Относительная позиция цены в категории.
"""
prices = sorted([p["final_price"] for p in all_products])
price = product["final_price"]
percentile = sum(1 for p in prices if p <= price) / len(prices) * 100

return {
"score": round(percentile),
"price": price,
"percentile": round(percentile, 1),
}


def score_sales(product: dict) -> dict:
"""
Измерение 5: Продажи.
Выручка и количество заказов.
"""
revenue = product.get("revenue", 0)
sales = product.get("sales", 0)

# Нормализация: 3M руб/мес = 100 баллов
score = min(revenue / 3_000_000 * 100, 100)

return {
"score": round(score),
"revenue": revenue,
"sales": sales,
}


def score_content_freshness(product: dict) -> dict:
"""
Измерение 6: Свежесть контента.
Если фото давно не обновлялись — карточка «устала».
Оценка на основе косвенных метрик (динамика позиций).
"""
# Прямых данных об обновлении фото в API нет,
# используем косвенный признак: высокие продажи +
# мало фото = контент давно не обновлялся
photos = product.get("picscount", 0)
revenue = product.get("revenue", 0)

if revenue > 500_000 and photos < 7:
score = 30 # Контент устарел — высокие продажи при плохом контенте
status = "устарел"
elif photos >= 10:
score = 85
status = "актуален"
else:
score = 55
status = "средний"

return {
"score": score,
"status": status,
}


# --- Полный конкурентный скоринг ---
def competitive_xray(
client_product: dict,
competitors: list,
keywords_data: dict,
all_products: list,
) -> dict:
"""
6-мерное сравнение клиента с ТОП-3 конкурентами.
Возвращает полную матрицу баллов и gap-анализ.
"""
participants = [client_product] + competitors
labels = ["Клиент"] + [f"Конкурент {chr(65 + i)}" for i in range(len(competitors))]

results = {}
for label, product in zip(labels, participants):
sku = product["id"]
kw = keywords_data.get(sku, [])

results[label] = {
"sku": sku,
"visual": score_visual_content(product),
"seo": score_seo(kw),
"social": score_social_proof(product),
"price": score_price_position(product, all_products),
"sales": score_sales(product),
"freshness": score_content_freshness(product),
}

# Общий балл (среднее по 6 измерениям)
scores = [
results[label]["visual"]["score"],
results[label]["seo"]["score"],
results[label]["social"]["score"],
results[label]["price"]["score"],
results[label]["sales"]["score"],
results[label]["freshness"]["score"],
]
results[label]["total_score"] = round(sum(scores) / len(scores))

return results


# --- Запуск ---
xray = competitive_xray(client, top3, keywords_data, products)

for label, data in xray.items():
print(f"\n{label} (SKU {data['sku']}): ИТОГО {data['total_score']}/100")
print(f" Визуал: {data['visual']['score']}/100 "
f"({data['visual']['photos']} фото, "
f"видео={'да' if data['visual']['has_video'] else 'нет'})")
print(f" SEO: {data['seo']['score']}/100 "
f"({data['seo']['in_top50']} ключей в ТОП-50)")
print(f" Соцдоказательство: {data['social']['score']}/100 "
f"({data['social']['comments']} отзывов, рейтинг {data['social']['rating']})")
print(f" Продажи: {data['sales']['score']}/100 "
f"(выручка {data['sales']['revenue']:,.0f} руб)")

Шаг 4. Конкурентная матрица

Результат анализа для конкретного клиента — наглядная таблица, которая сразу показывает, где проблемы:

МетрикаКлиентКонкурент AКонкурент BКонкурент C
Фото5141012
ВидеоНетЕстьЕстьНет
3DНетНетНетНет
Ключевых слов в ТОП-5023876544
Рейтинг4.24.84.64.5
Отзывов891 200450320
Выручка/мес500K3.2M1.8M1.1M
Общий балл28/10082/10064/10051/100

Шаг 5. Gap-анализ — где клиент теряет больше всего

def calculate_gaps(xray_results: dict) -> list:
"""
Рассчитывает gap клиента по каждому измерению
относительно лучшего конкурента.
"""
client = xray_results["Клиент"]
dimensions = ["visual", "seo", "social", "price", "sales", "freshness"]
dimension_names = {
"visual": "Визуальный контент",
"seo": "SEO-видимость",
"social": "Социальное доказательство",
"price": "Ценовое позиционирование",
"sales": "Продажи",
"freshness": "Свежесть контента",
}

gaps = []
for dim in dimensions:
client_score = client[dim]["score"]

# Лучший балл среди конкурентов
best_score = max(
data[dim]["score"]
for label, data in xray_results.items()
if label != "Клиент"
)
best_label = max(
(label for label in xray_results if label != "Клиент"),
key=lambda l: xray_results[l][dim]["score"],
)

gap = best_score - client_score
gap_pct = gap / best_score * 100 if best_score > 0 else 0

gaps.append({
"dimension": dimension_names[dim],
"client_score": client_score,
"best_score": best_score,
"best_competitor": best_label,
"gap_points": gap,
"gap_pct": round(gap_pct, 1),
"severity": (
"КРИТИЧНО" if gap > 40
else "ВЫСОКИЙ" if gap > 20
else "СРЕДНИЙ" if gap > 10
else "НИЗКИЙ"
),
})

# Сортируем: самые большие gap-ы наверху
gaps.sort(key=lambda g: g["gap_points"], reverse=True)
return gaps


gaps = calculate_gaps(xray)

print("GAP-АНАЛИЗ: Клиент vs лучший конкурент\n")
for g in gaps:
print(f" [{g['severity']}] {g['dimension']}: "
f"{g['client_score']} vs {g['best_score']} ({g['best_competitor']}), "
f"gap = -{g['gap_points']} ({g['gap_pct']}%)")

Пример вывода gap-анализа:

ИзмерениеКлиентЛучший конкурентGapSeverity
SEO-видимость23/10087/100 (Конкурент A)-64КРИТИЧНО
Социальное доказательство18/10074/100 (Конкурент A)-56КРИТИЧНО
Визуальный контент17/10077/100 (Конкурент A)-60КРИТИЧНО
Продажи17/100100/100 (Конкурент A)-83КРИТИЧНО
Свежесть контента30/10085/100 (Конкурент B)-55КРИТИЧНО
Ценовое позиционирование45/10062/100 (Конкурент B)-17СРЕДНИЙ
Чего НЕ делать при конкурентном анализе

Не копируйте конкурентов слепо. Цель рентгена — найти gap-ы, а не превратиться в клон. Конкурент A имеет 14 фото — но это не значит, что нужно повторить его ракурсы. Нужно закрыть количественный gap (добавить фото), но дифференцироваться качественно (другой стиль, другие акценты).

Распространённые ошибки:

  • Копировать стиль фото лидера — WB штрафует за слишком похожие карточки
  • Накручивать отзывы вместо улучшения контента — временный эффект, риск блокировки
  • Снижать цену как единственную стратегию — это гонка на дно, а не решение
  • Игнорировать свои сильные стороны — если рейтинг упаковки у клиента лучше конкурентов, это нужно усилить, а не забыть

Действие Fotofactor

На основе конкурентного рентгена Fotofactor генерирует брендированный PDF-отчёт на 20-30 страниц — самый мощный инструмент продажи контентных услуг.

Структура PDF-отчёта

РазделСтраницыСодержимое
Обложка1Категория, дата, логотип Fotofactor, SKU клиента
Executive Summary2-3Общий балл клиента vs ТОП-3, главные выводы
Конкурентная матрица4-5Полная таблица 6 измерений с цветовой кодировкой
Визуальный аудит6-9Скриншоты карточек: клиент vs каждый конкурент с аннотациями
SEO-сравнение10-13Пересечение ключей, уникальные ключи конкурентов, позиции
Рейтинг и отзывы14-15Сравнение social proof, типичные жалобы
Финансовый разрыв16-17Сколько денег клиент теряет из-за каждого gap-а
План действий18-22Пошаговый план с приоритетами, сроками и стоимостью
Скриншоты конкурентов23-28Аннотированные скриншоты карточек ТОП-3
О Fotofactor29-30Услуги, портфолио, кейсы, контакты

Визуализация: скриншоты с аннотациями

Ключевой элемент отчёта — визуальное сравнение карточек. Для каждого конкурента:

  1. Скриншот карточки клиента — с красными стрелками на проблемах
  2. Скриншот карточки конкурента — с зелёными маркерами на преимуществах
  3. Side-by-side — клиент слева, конкурент справа, gap подписан

Пример аннотаций:

  • «У вас 5 фото, у конкурента A — 14. Разница: 9 фотографий»
  • «Конкурент B использует видеообзор 45 сек. У вас видео отсутствует»
  • «Инфографика конкурента C содержит размерную сетку. У вас — только фото товара»

Конкретный план действий

Самая важная часть отчёта — пошаговый план с приоритетами:

def generate_action_plan(gaps: list, client_data: dict) -> list:
"""
Генерирует приоритизированный план действий
на основе gap-анализа.
"""
actions = []

for gap in gaps:
if gap["severity"] in ("КРИТИЧНО", "ВЫСОКИЙ"):
dim = gap["dimension"]

if "Визуальный" in dim:
photo_gap = gap["best_score"] - gap["client_score"]
actions.append({
"priority": 1,
"action": f"Добавить {int(photo_gap * 15 / 100)} фото, "
f"создать видеообзор 30-60 сек",
"impact": "Рост конверсии на 25-40%",
"cost": "50 000 - 90 000 руб",
"timeline": "2-3 недели",
})

elif "SEO" in dim:
actions.append({
"priority": 2,
"action": f"Оптимизировать {gap['gap_points']} "
f"ключевых слов из семантики конкурентов",
"impact": "Рост органического трафика на 50-100%",
"cost": "20 000 - 35 000 руб",
"timeline": "1-2 недели",
})

elif "Социальное" in dim:
actions.append({
"priority": 3,
"action": "Улучшить контент для снижения возвратов "
"+ стимулировать отзывы через вкладыши",
"impact": "Рост рейтинга с 4.2 до 4.5+",
"cost": "15 000 - 25 000 руб",
"timeline": "1-3 месяца (накопительный эффект)",
})

actions.sort(key=lambda a: a["priority"])
return actions

Пример плана для клиента из матрицы выше:

ПриоритетДействиеОжидаемый эффектСтоимостьСрок
1Добавить 9 фото + видеообзор 45 секКонверсия +25-40%70 000 руб2 недели
2SEO-оптимизация: добавить 64 ключевых словаОрганический трафик +80%30 000 руб1 неделя
3Инфографика с размерами и характеристикамиСнижение возвратов на 5-8%25 000 руб1 неделя
4Rich-контент и A+ описаниеВремя на карточке +20%20 000 руб1 неделя
ИтогоПолный рестайлинг карточкиРост выручки x2-3145 000 руб4-5 недель
Как презентовать отчёт клиенту

Никогда не отправляйте PDF без звонка. Правильная последовательность:

  1. Тизер в мессенджере: «Подготовили конкурентный анализ вашей карточки. Нашли 3 критических разрыва — хотите посмотреть?»
  2. Звонок 30 минут: листаете PDF вместе с клиентом, останавливаясь на скриншотах конкурентов
  3. Ключевой момент: откройте слайд с side-by-side сравнением фото. Пауза. Дайте клиенту самому сказать: «Да, у него лучше»
  4. План действий: не спрашивайте «хотите ли?», спрашивайте «с чего начнём — с фото или SEO?»
  5. Фиксация: отправьте PDF + коммерческое предложение в течение 1 часа после звонка

Средняя конверсия при этом подходе: 70-80%. Отчёт продаёт сам себя — вы просто показываете gap-ы.

Результат для клиента

Что получает клиент

  • Кристально чёткая конкурентная картина — не «мне кажется, у конкурента лучше», а «у конкурента A в 2.8 раза больше фото, в 3.8 раза больше ключевых слов и в 13 раз больше отзывов»
  • Конкретные gap-ы с числами — каждый разрыв измерен, приоритизирован и привязан к действию
  • Urgency через визуальное сравнение — скриншот карточки клиента рядом с конкурентом создаёт мгновенное понимание: «Мне нужно это исправить»
  • Готовый план действий — не абстрактные «улучшите контент», а «добавьте 9 фото, снимите видео, оптимизируйте 64 ключевых слова»
  • Финансовая оценка потерь — «Разрыв в контенте стоит вам ~2.7M руб/мес упущенной выручки»

Экономика для Fotofactor

МетрикаЗначение
Время на создание отчёта2-3 часа (с шаблоном — 1 час)
Стоимость MPStats-запросов5 API-вызовов на отчёт
Конверсия отчёта в сделку70-80%
Средний чек сделки после отчёта100 000 - 200 000 руб
Конверсия стандартного КП (без отчёта)15-25%
Рост конверсииx3-4 по сравнению с обычным КП
Почему конверсия 70-80% — это реально

Стандартное коммерческое предложение говорит: «Мы сделаем вам красивые фото». Конкурентный рентген говорит: «У вас 5 фото, у лидера 14. У вас 23 ключа в ТОП-50, у лидера 87. Вот план, как закрыть разрыв за 4 недели». Клиент не может возразить цифрам — он видит проблему и понимает решение. Единственный вопрос — «когда начинаем?».

Средняя сделка с конкурентного рентгена: 100 000-200 000 руб (полный рестайлинг карточки). Это в 2-3 раза выше, чем при «холодных» продажах, потому что клиент сам понимает объём работы.

Воронка конкурентного рентгена

flowchart TD
A["Клиент интересуется\nулучшением карточки"] --> B["Fotofactor предлагает\nбесплатный конкурентный\nрентген"]
B --> C["Генерация отчёта\n5 API-вызовов + 1-2 часа"]
C --> D["Презентация по звонку\n30 минут с PDF"]
D --> E{"Клиент видит gap-ы\nи готов действовать?"}
E -->|"Да (70-80%)"| F["Подписание договора\n100-200K руб"]
E -->|"Не сейчас (15-20%)"| G["Отчёт остаётся\nу клиента — возврат\nчерез 1-3 месяца"]
E -->|"Нет (5-10%)"| H["Клиент в базе\nдля ретаргетинга"]
F --> I["Полный рестайлинг\n4-5 недель"]
I --> J["Мониторинг результатов\nподписка 25K/мес"]

Unit-экономика

Вход:  1 SKU клиента + категория (5 API-запросов)

Анализ: 6-мерное сравнение + gap + план (~2 часа)

Отчёт: PDF 20-30 страниц + презентация

Сделка: 100 000 - 200 000 руб (рестайлинг)
+ 25 000 руб/мес (мониторинг)

LTV: 400 000 - 700 000 руб/год на клиента

Что дальше