Skip to content

Sales Funnel Analytics

This guide covers the Wildberries Sales Funnel API (v3) and explains how to use the SDK to retrieve, filter, and analyze product performance data at every stage of the buyer journey.

Target Audience: Developers building analytics dashboards, product managers tracking conversion metrics, and data analysts working with Wildberries seller data

Prerequisites: SDK installed and configured, valid API key with Analytics permissions

Estimated Reading Time: 25 minutes


Table of Contents

  1. What is the Sales Funnel
  2. SDK Methods
  3. Key Metrics Reference
  4. Filtering and Sorting
  5. Practical Scenarios
  6. CSV Reports for Extended Periods
  7. Rate Limits
  8. Error Handling
  9. Related Resources

What is the Sales Funnel

The sales funnel on Wildberries tracks the buyer journey from initial product discovery through to a completed purchase that the customer keeps. The Wildberries API provides quantitative metrics for each stage, allowing you to measure how effectively your products convert browsing activity into revenue.

Funnel Stages

Impressions (openCount)
    Product card views -- the customer opens the product page
        |
        |  addToCartPercent  (view-to-cart conversion)
        v
Cart (cartCount)
    Customer adds the product to their cart
        |
        |  cartToOrderPercent  (cart-to-order conversion)
        v
Orders (orderCount / orderSum)
    Customer places the order and pays
        |
        |  buyoutPercent  (order-to-buyout conversion)
        v
Purchases (buyoutCount / buyoutSum)
    Customer receives and keeps the product

At each transition, a percentage of customers drops off. The SDK returns conversion rates for every transition so you can identify where products lose the most potential buyers.

Cancellations (cancelCount, cancelSum) are tracked separately and represent orders that were placed but later cancelled before or after delivery.


SDK Methods

The Analytics module provides three methods for sales funnel data. Each targets a different analytical use case.

getSalesFunnelProducts -- Summary Report

Returns a paginated list of products with aggregated funnel metrics for a selected period. Optionally compares the selected period against a past period, producing delta values for every metric.

Period limit: up to 365 days.

typescript
import { WildberriesSDK } from 'daytona-wildberries-typescript-sdk';

const sdk = new WildberriesSDK({ apiKey: process.env.WB_API_KEY! });

const report = await sdk.analytics.getSalesFunnelProducts({
  selectedPeriod: {
    start: '2026-01-01',
    end: '2026-01-31',
  },
  pastPeriod: {
    start: '2025-12-01',
    end: '2025-12-31',
  },
  orderBy: { field: 'orderSum', mode: 'desc' },
  limit: 20,
  offset: 0,
  skipDeletedNm: true,
});

for (const entry of report.products) {
  const { product, statistic } = entry;
  const current = statistic.selected;
  console.log(
    `${product.title} (nmId: ${product.nmId})`,
    `| Views: ${current.openCount}`,
    `| Cart: ${current.cartCount}`,
    `| Orders: ${current.orderCount} (${current.orderSum} ${report.currency})`,
    `| Buyout: ${current.buyoutCount} (${current.conversions.buyoutPercent}%)`,
  );

  // Period-over-period comparison (available when pastPeriod is provided)
  if (statistic.comparison) {
    console.log(
      `  Delta: orders ${statistic.comparison.orderCountDynamic > 0 ? '+' : ''}${statistic.comparison.orderCountDynamic}%`,
      `| buyouts ${statistic.comparison.buyoutCountDynamic > 0 ? '+' : ''}${statistic.comparison.buyoutCountDynamic}%`,
    );
  }
}

Request parameters:

ParameterTypeRequiredDescription
selectedPeriodDatePeriodYesStart and end dates (YYYY-MM-DD) for the report
pastPeriodDatePeriodNoComparison period. When provided, response includes comparison deltas
nmIdsnumber[]NoFilter by WB article IDs
brandNamesstring[]NoFilter by brand names
subjectIdsnumber[]NoFilter by subject (category) IDs
tagIdsnumber[]NoFilter by tag IDs
skipDeletedNmbooleanNoExclude deleted product cards from results
orderBySalesFunnelOrderByNoSort field and direction (asc or desc)
limitnumberNoNumber of products per page
offsetnumberNoNumber of products to skip (for pagination)

getSalesFunnelProductsHistory -- Daily/Weekly Breakdown

Returns day-by-day or week-by-week statistics for specific products. Use this method to track how individual product metrics change over time.

Period limit: maximum 7 days.

Note: The nmIds parameter is required for this method.

typescript
import { WildberriesSDK } from 'daytona-wildberries-typescript-sdk';

const sdk = new WildberriesSDK({ apiKey: process.env.WB_API_KEY! });

const history = await sdk.analytics.getSalesFunnelProductsHistory({
  selectedPeriod: {
    start: '2026-03-22',
    end: '2026-03-28',
  },
  nmIds: [268913787],
  aggregationLevel: 'day',
  skipDeletedNm: true,
});

// Response is an array -- one element per product
for (const item of history) {
  console.log(`Product: ${item.product.title} (nmId: ${item.product.nmId})`);

  for (const day of item.history) {
    console.log(
      `  ${day.date}`,
      `| Views: ${day.openCount}`,
      `| Cart: ${day.cartCount} (${day.addToCartConversion}%)`,
      `| Orders: ${day.orderCount} (${day.cartToOrderConversion}%)`,
      `| Buyout: ${day.buyoutCount} (${day.buyoutPercent}%)`,
    );
  }
}

Request parameters:

ParameterTypeRequiredDescription
selectedPeriodDatePeriodYesStart and end dates (max 7-day span)
nmIdsnumber[]YesWB article IDs to retrieve history for
skipDeletedNmbooleanNoExclude deleted product cards
aggregationLevel'day' | 'week'NoGranularity of the breakdown. Defaults to 'day'

getSalesFunnelGroupedHistory -- Grouped by Category/Brand/Tag

Returns daily or weekly statistics grouped by subjects, brands, or tags rather than individual products. Use this to analyze performance trends at the category or brand level.

Period limit: maximum 7 days.

typescript
import { WildberriesSDK } from 'daytona-wildberries-typescript-sdk';

const sdk = new WildberriesSDK({ apiKey: process.env.WB_API_KEY! });

const grouped = await sdk.analytics.getSalesFunnelGroupedHistory({
  selectedPeriod: {
    start: '2026-03-22',
    end: '2026-03-28',
  },
  subjectIds: [105],       // e.g., "T-shirts" category
  aggregationLevel: 'day',
  skipDeletedNm: true,
});

for (const group of grouped) {
  console.log(`Group: ${group.product.subjectName} / ${group.product.brandName}`);
  for (const day of group.history) {
    console.log(
      `  ${day.date}: ${day.orderCount} orders, ${day.buyoutPercent}% buyout`,
    );
  }
}

Request parameters:

ParameterTypeRequiredDescription
selectedPeriodDatePeriodYesStart and end dates (max 7-day span)
brandNamesstring[]NoFilter by brand names
subjectIdsnumber[]NoFilter by subject (category) IDs
tagIdsnumber[]NoFilter by tag IDs
skipDeletedNmbooleanNoExclude deleted product cards
aggregationLevel'day' | 'week'NoGranularity of the breakdown. Defaults to 'day'

Key Metrics Reference

Funnel Volume Metrics

MetricTypeDescription
openCountnumberProduct card views (impressions)
cartCountnumberTimes the product was added to cart
orderCountnumberNumber of orders placed
orderSumnumberTotal monetary value of orders
buyoutCountnumberNumber of completed purchases (kept by customer)
buyoutSumnumberTotal monetary value of buyouts
cancelCountnumberNumber of cancelled orders
cancelSumnumberTotal monetary value of cancellations

Conversion Metrics

The conversions object contains the three stage-to-stage conversion rates:

MetricTypeDescription
addToCartPercentnumberPercentage of viewers who added the product to cart
cartToOrderPercentnumberPercentage of cart additions that converted to orders
buyoutPercentnumberPercentage of orders that were completed as purchases

Pricing and Revenue

MetricTypeDescription
avgPricenumberAverage selling price for the period
avgOrdersCountPerDaynumberAverage number of orders per day
shareOrderPercentnumberProduct's share of total seller revenue

Engagement and Logistics

MetricTypeDescription
addToWishlistnumberTimes the product was added to the Wishlist
timeToReadySalesFunnelTimeToReadyAverage delivery time (days, hours, minutes)
localizationPercentnumberPercentage of orders that are intra-regional (same region as warehouse)

WB Club Metrics

The wbClub object contains metrics specifically for orders placed by WB Club members:

MetricTypeDescription
wbClub.orderCountnumberOrders from WB Club members
wbClub.orderSumnumberOrder value from WB Club members
wbClub.buyoutCountnumberBuyouts by WB Club members
wbClub.buyoutSumnumberBuyout value from WB Club members
wbClub.buyoutPercentnumberBuyout rate for WB Club members
wbClub.avgOrderCountPerDaynumberAverage daily orders from WB Club

History-Specific Metrics

The daily/weekly history endpoints (getSalesFunnelProductsHistory and getSalesFunnelGroupedHistory) return SalesFunnelHistory records with these fields per time period:

FieldTypeDescription
datestringDate of the data point
openCountnumberViews for that day/week
cartCountnumberCart additions
orderCountnumberOrders placed
orderSumnumberOrder value
buyoutCountnumberCompleted purchases
buyoutSumnumberBuyout value
buyoutPercentnumberBuyout rate
addToCartConversionnumberView-to-cart conversion rate
cartToOrderConversionnumberCart-to-order conversion rate
addToWishlistCountnumberWishlist additions

Filtering and Sorting

Filter Parameters

All three methods support filtering to narrow down the dataset. The summary method (getSalesFunnelProducts) supports all filters; the history methods support a subset.

nmIds -- Filter by WB Article

Pass an array of Wildberries article numbers to retrieve data for specific products. This is the most common filter when you want to monitor a known set of SKUs.

typescript
// Monitor your top 5 products
const report = await sdk.analytics.getSalesFunnelProducts({
  selectedPeriod: { start: '2026-03-01', end: '2026-03-28' },
  nmIds: [268913787, 395996251, 112334455, 998877665, 554433221],
});

Supported by: getSalesFunnelProducts, getSalesFunnelProductsHistory

brandNames -- Filter by Brand

Useful when your seller account manages multiple brands and you want to analyze brand-level performance.

typescript
const report = await sdk.analytics.getSalesFunnelProducts({
  selectedPeriod: { start: '2026-03-01', end: '2026-03-28' },
  brandNames: ['MyBrand', 'SecondBrand'],
  orderBy: { field: 'orderSum', mode: 'desc' },
  limit: 50,
  offset: 0,
});

Supported by: getSalesFunnelProducts, getSalesFunnelGroupedHistory

subjectIds -- Filter by Subject (Category)

Subject IDs correspond to Wildberries product categories (e.g., T-shirts, Sneakers). Use this when comparing performance across categories.

typescript
const grouped = await sdk.analytics.getSalesFunnelGroupedHistory({
  selectedPeriod: { start: '2026-03-22', end: '2026-03-28' },
  subjectIds: [105, 210],   // Two categories
  aggregationLevel: 'day',
});

Supported by: getSalesFunnelProducts, getSalesFunnelGroupedHistory

tagIds -- Filter by Tag

Tags are seller-defined labels assigned to products in the Wildberries seller portal. Use this to segment analytics by your own organizational structure (e.g., "Summer Collection", "Clearance").

typescript
const report = await sdk.analytics.getSalesFunnelProducts({
  selectedPeriod: { start: '2026-03-01', end: '2026-03-28' },
  tagIds: [42],   // "Summer Collection" tag
  orderBy: { field: 'buyoutCount', mode: 'desc' },
  limit: 100,
  offset: 0,
});

Supported by: getSalesFunnelProducts, getSalesFunnelGroupedHistory

skipDeletedNm -- Exclude Deleted Cards

When set to true, products that have been deleted from your catalog are excluded from results. This keeps your analytics clean when products are discontinued.

Supported by: all three methods.

Sorting (getSalesFunnelProducts only)

The orderBy parameter controls the sort order of the paginated result set. It accepts a field and a mode ('asc' or 'desc').

Available sort fields:

FieldDescription
openCardSort by product card views
addToCartSort by cart additions
orderCountSort by order quantity
orderSumSort by order revenue
buyoutCountSort by buyout quantity
buyoutSumSort by buyout revenue
cancelCountSort by cancellations
cancelSumSort by cancellation value
avgPriceSort by average price
stockMpQtySort by seller warehouse stock
stockWbQtySort by WB warehouse stock
shareOrderPercentSort by revenue share
addToWishlistSort by wishlist additions
timeToReadySort by delivery time
localizationPercentSort by regional order percentage

WB Club fields are also available with the wbClub. prefix (e.g., wbClub.orderCount, wbClub.buyoutPercent).


Practical Scenarios

ABC Analysis of Product Assortment

ABC analysis classifies products into three groups by their contribution to total revenue. Group A products generate roughly 80% of revenue, Group B the next 15%, and Group C the remaining 5%.

typescript
import { WildberriesSDK } from 'daytona-wildberries-typescript-sdk';

const sdk = new WildberriesSDK({ apiKey: process.env.WB_API_KEY! });

async function abcAnalysis(startDate: string, endDate: string) {
  // Fetch all products sorted by revenue descending
  const allProducts: Array<{
    nmId: number;
    title: string;
    revenue: number;
    buyoutPercent: number;
  }> = [];

  let offset = 0;
  const pageSize = 100;
  let hasMore = true;

  while (hasMore) {
    const page = await sdk.analytics.getSalesFunnelProducts({
      selectedPeriod: { start: startDate, end: endDate },
      orderBy: { field: 'buyoutSum', mode: 'desc' },
      limit: pageSize,
      offset,
      skipDeletedNm: true,
    });

    for (const entry of page.products) {
      allProducts.push({
        nmId: entry.product.nmId,
        title: entry.product.title,
        revenue: entry.statistic.selected.buyoutSum,
        buyoutPercent: entry.statistic.selected.conversions.buyoutPercent,
      });
    }

    hasMore = page.products.length === pageSize;
    offset += pageSize;
  }

  // Calculate cumulative revenue share
  const totalRevenue = allProducts.reduce((sum, p) => sum + p.revenue, 0);
  let cumulativeShare = 0;

  const classified = allProducts.map((product) => {
    cumulativeShare += product.revenue / totalRevenue;
    let group: 'A' | 'B' | 'C';
    if (cumulativeShare <= 0.8) {
      group = 'A';
    } else if (cumulativeShare <= 0.95) {
      group = 'B';
    } else {
      group = 'C';
    }
    return { ...product, group };
  });

  // Summary
  const groups = { A: 0, B: 0, C: 0 };
  for (const item of classified) {
    groups[item.group]++;
  }

  console.log(`ABC Analysis for ${startDate} to ${endDate}:`);
  console.log(`  Total products: ${classified.length}`);
  console.log(`  Total revenue: ${totalRevenue.toLocaleString()}`);
  console.log(`  Group A: ${groups.A} products (80% of revenue)`);
  console.log(`  Group B: ${groups.B} products (next 15%)`);
  console.log(`  Group C: ${groups.C} products (remaining 5%)`);

  return classified;
}

const result = await abcAnalysis('2026-01-01', '2026-03-28');

Comparing Conversion Rates Across Periods

Identify whether your conversion metrics are improving or declining by comparing the current month against the previous month.

typescript
import { WildberriesSDK } from 'daytona-wildberries-typescript-sdk';

const sdk = new WildberriesSDK({ apiKey: process.env.WB_API_KEY! });

async function compareConversions() {
  const report = await sdk.analytics.getSalesFunnelProducts({
    selectedPeriod: {
      start: '2026-03-01',
      end: '2026-03-28',
    },
    pastPeriod: {
      start: '2026-02-01',
      end: '2026-02-28',
    },
    orderBy: { field: 'orderSum', mode: 'desc' },
    limit: 50,
    offset: 0,
    skipDeletedNm: true,
  });

  console.log('Product Conversion Comparison (March vs February):');
  console.log('---------------------------------------------------');

  for (const entry of report.products) {
    const { product, statistic } = entry;
    const current = statistic.selected.conversions;
    const past = statistic.past?.conversions;

    console.log(`\n${product.title} (${product.nmId}):`);
    console.log(`  Add-to-cart:    ${current.addToCartPercent}%`);
    console.log(`  Cart-to-order:  ${current.cartToOrderPercent}%`);
    console.log(`  Buyout:         ${current.buyoutPercent}%`);

    if (past) {
      const cartDelta = current.addToCartPercent - past.addToCartPercent;
      const orderDelta = current.cartToOrderPercent - past.cartToOrderPercent;
      const buyoutDelta = current.buyoutPercent - past.buyoutPercent;

      console.log(`  vs. past period:`);
      console.log(`    Add-to-cart:   ${cartDelta > 0 ? '+' : ''}${cartDelta.toFixed(1)}pp`);
      console.log(`    Cart-to-order: ${orderDelta > 0 ? '+' : ''}${orderDelta.toFixed(1)}pp`);
      console.log(`    Buyout:        ${buyoutDelta > 0 ? '+' : ''}${buyoutDelta.toFixed(1)}pp`);
    }
  }
}

await compareConversions();

Monitor a specific product's performance day-by-day to detect sudden changes or the impact of promotions.

typescript
import { WildberriesSDK } from 'daytona-wildberries-typescript-sdk';

const sdk = new WildberriesSDK({ apiKey: process.env.WB_API_KEY! });

async function trackDailyTrends(nmId: number) {
  const history = await sdk.analytics.getSalesFunnelProductsHistory({
    selectedPeriod: {
      start: '2026-03-22',
      end: '2026-03-28',
    },
    nmIds: [nmId],
    aggregationLevel: 'day',
    skipDeletedNm: true,
  });

  if (history.length === 0) {
    console.log(`No data found for nmId ${nmId}`);
    return;
  }

  const item = history[0];
  console.log(`Daily trends for: ${item.product.title}`);
  console.log(`Period: ${item.history[0]?.date} to ${item.history[item.history.length - 1]?.date}`);
  console.log('');

  // Calculate averages
  const days = item.history;
  const avgViews = days.reduce((s, d) => s + d.openCount, 0) / days.length;
  const avgOrders = days.reduce((s, d) => s + d.orderCount, 0) / days.length;

  console.log(`  Average daily views:  ${avgViews.toFixed(0)}`);
  console.log(`  Average daily orders: ${avgOrders.toFixed(1)}`);
  console.log('');

  // Day-by-day breakdown
  for (const day of days) {
    const viewsVsAvg = ((day.openCount - avgViews) / avgViews * 100).toFixed(0);
    const marker = Math.abs(Number(viewsVsAvg)) > 30 ? ' <-- significant change' : '';

    console.log(
      `  ${day.date}:`,
      `Views: ${day.openCount} (${Number(viewsVsAvg) > 0 ? '+' : ''}${viewsVsAvg}% vs avg)`,
      `| Cart: ${day.addToCartConversion}%`,
      `| Orders: ${day.orderCount}`,
      `| Buyout: ${day.buyoutPercent}%`,
      marker,
    );
  }
}

await trackDailyTrends(268913787);

CSV Reports for Extended Periods

The three JSON-based sales funnel methods described above are limited to 365 days (summary) or 7 days (history). For longer time ranges or very large datasets, use the CSV report endpoints instead.

CSV reports are generated asynchronously. You create a report generation task, poll for its status, and then download the resulting ZIP archive containing a CSV file.

typescript
import { WildberriesSDK } from 'daytona-wildberries-typescript-sdk';

const sdk = new WildberriesSDK({ apiKey: process.env.WB_API_KEY! });

// Step 1: Create a report generation task
const task = await sdk.analytics.createNmReportDownload({
  reportType: 'SALES_FUNNEL_PRODUCT',
  userReportName: 'Q1 2026 Sales Funnel',
  params: {
    selectedPeriod: {
      start: '2026-01-01',
      end: '2026-03-31',
    },
    aggregationLevel: 'month',
    skipDeletedNm: true,
  },
});

console.log('Report task created:', task.data?.downloadId);

CSV reports require a Jam subscription for certain report types. If you need to detect your subscription tier before making requests, see the Jam Subscription Detection guide.

For a complete walkthrough of the CSV report workflow (creation, polling, download, and parsing), see the Seller Analytics CSV Reports guide.


Rate Limits

All three sales funnel methods share the same rate limit:

  • 3 requests per minute
  • 20-second interval between requests
  • Burst limit: 3 requests

The SDK enforces these limits automatically through its built-in rate limiter. If you exceed the limit, the SDK throws a RateLimitError with retry timing information.

When paginating through large datasets, add a brief delay between pages:

typescript
const delay = (ms: number) => new Promise((resolve) => setTimeout(resolve, ms));

let offset = 0;
const pageSize = 100;

while (true) {
  const page = await sdk.analytics.getSalesFunnelProducts({
    selectedPeriod: { start: '2026-01-01', end: '2026-03-28' },
    orderBy: { field: 'orderSum', mode: 'desc' },
    limit: pageSize,
    offset,
  });

  // Process page...

  if (page.products.length < pageSize) break;
  offset += pageSize;

  // Respect the 20-second interval
  await delay(20_000);
}

Error Handling

typescript
import { WildberriesSDK } from 'daytona-wildberries-typescript-sdk';
import {
  RateLimitError,
  AuthenticationError,
  ValidationError,
} from 'daytona-wildberries-typescript-sdk';

const sdk = new WildberriesSDK({ apiKey: process.env.WB_API_KEY! });

try {
  const report = await sdk.analytics.getSalesFunnelProducts({
    selectedPeriod: { start: '2026-03-01', end: '2026-03-28' },
    limit: 20,
    offset: 0,
  });
  // Process report...
} catch (error) {
  if (error instanceof RateLimitError) {
    console.error(`Rate limited. Retry after ${error.retryAfter}ms`);
  } else if (error instanceof AuthenticationError) {
    console.error('Invalid API key. Check your credentials.');
  } else if (error instanceof ValidationError) {
    console.error('Invalid request parameters:', error.message);
  } else {
    throw error;
  }
}

Common validation errors:

  • Period exceeds maximum: The summary endpoint allows up to 365 days; the history endpoints allow up to 7 days. Exceeding these limits returns a 400 error.
  • Missing required nmIds: The getSalesFunnelProductsHistory method requires at least one nmId.
  • Invalid date format: Dates must be in YYYY-MM-DD format.

Made with ❤️ for the Wildberries developer community