> ## Documentation Index
> Fetch the complete documentation index at: https://docs.bily.ai/llms.txt
> Use this file to discover all available pages before exploring further.

# Frequently asked questions

> Find direct answers about Bily setup, events, identity, analytics, API, MCP, privacy, and production use.

These answers reflect the public Bily SDK, API, and MCP contracts. Open the linked guide when you need implementation steps or a complete reference.

## Understand Bily

<AccordionGroup>
  <Accordion title="What does Bily do?">
    Bily gives websites a programmable customer data and activation layer. It brings browser events, trusted server workflows, and compatible AI clients into the same website, organization, and store context.

    Start with [What is Bily?](/concepts/what-is-bily) for the full product model.
  </Accordion>

  <Accordion title="What are Bily Apps?">
    Bily Apps add installable capabilities through a governed website connection. They remain separate from the SDK, API, and MCP developer surfaces.

    See [Bily Apps](/concepts/bily-apps) for their lifecycle and boundaries.
  </Accordion>

  <Accordion title="What is the difference between the SDK, API, and MCP?">
    Use the SDK to send browser events. Use the API when trusted server code needs versioned Bily data or actions.

    Use MCP when a compatible AI client needs to discover current operations through `search` and run focused work through `execute`.

    The [API or MCP selection guide](/guides/api-mcp-selection) helps when a workflow crosses more than one surface.
  </Accordion>

  <Accordion title="Where should I start?">
    Define your events and owners first. Then choose one browser installation path.

    Verify a small set of high-value events in staging before you add production automation.

    Use [implementation planning](/guides/implementation-planning), then follow the [quickstart](/quickstart).
  </Accordion>

  <Accordion title="Do I need all three developer surfaces?">
    No. Choose only what the workflow needs.

    A website may use only the SDK. A scheduled backend integration may use the API. An operator may connect an AI client through MCP. You can combine them without treating one as a substitute for another.
  </Accordion>
</AccordionGroup>

## Install browser tracking

<AccordionGroup>
  <Accordion title="Should I use the raw script or the npm package?">
    Use the exact raw script for plain HTML or a site-managed script field. Use `@bilyai/js` for applications with an npm build, including React and Next.js.

    Install only one method on each website surface.
  </Accordion>

  <Accordion title="Where do I find the tracking URL?">
    Select the intended store. Open **Bily > Settings > Apps > More settings > Install tracking**, choose the site's technology, and copy the complete script or SDK snippet.

    Keep every query parameter. Do not rebuild the URL from only its hostname.
  </Accordion>

  <Accordion title="Why must the exact tracking URL stay unchanged?">
    The full URL is the installation contract. Its query parameters and encoded characters can select the intended store or configuration.

    Passing only the origin or rebuilding the path can change the installation.
  </Accordion>

  <Accordion title="Does Bily track the first page automatically?">
    Yes. The browser script records the initial document `PageView` automatically. Do not send another page view from the initial mount.
  </Accordion>

  <Accordion title="How do I track routes in a single-page application?">
    Send one explicit `PageView` after each later committed route. Include the final `window.location.href` and `document.title`.

    Skip the initial route callback and ignore repeated notifications for the same URL.

    See [Page views](/guides/pageviews).
  </Accordion>

  <Accordion title="Can I call track() before Bily finishes loading?">
    Yes. The SDK keeps early calls in a bounded in-memory queue and sends them in order when the browser runtime becomes ready.

    The default queue holds 100 calls. You can set it from 1 to 1,000.
  </Accordion>

  <Accordion title="What does ready() prove?">
    `ready()` confirms that the Bily browser runtime can accept queued calls. It rejects when loading fails or times out.

    It does not acknowledge a specific event or prove ingestion.
  </Accordion>

  <Accordion title="Can I enable debug logging in production?">
    Use `debug: true` temporarily while you validate a release. It logs SDK lifecycle details without logging event payloads.

    Turn it off after verification to keep the console quiet.
  </Accordion>

  <Accordion title="What happens if init() runs twice?">
    Repeating `init()` with the same URL does not load another script. Bily ignores a different URL after loading starts or completes.

    Keep one configuration owner. Select the correct environment URL before the first call.
  </Accordion>

  <Accordion title="Is the SDK safe during server rendering?">
    Yes. Public SDK methods avoid browser work during server rendering. `track()` becomes a no-op, `ready()` resolves, and `getBilyTrackingId()` returns `null`.

    Initialize Bily from client-mounted browser code.
  </Accordion>
</AccordionGroup>

## Design reliable events

<AccordionGroup>
  <Accordion title="Can I send custom events?">
    Yes. `track()` accepts Bily's known event names and any custom non-empty string.

    Use stable snake\_case names for application outcomes. Keep changing IDs or values in the payload.
  </Accordion>

  <Accordion title="Are event names case-sensitive?">
    Yes. Copy the exact capitalization from the [event reference](/api-reference/events).

    The SDK accepts documented compatibility aliases, but new code should use current names.
  </Accordion>

  <Accordion title="When should an event fire?">
    Send an event only after its named outcome becomes true. For example, send `workspace_created` after creation succeeds, not when the user clicks submit.
  </Accordion>

  <Accordion title="Which fields does the SDK add automatically?">
    The SDK adds the browser source and a Bily browser tracking ID when available. It also adds an ISO timestamp when `ts` is absent and generates `event_id` when you do not provide one.
  </Accordion>

  <Accordion title="Does event_id prevent duplicates?">
    Use `event_id` to identify one logical outcome and correlate related work. It is not an ingestion receipt or a promise of exactly-once delivery.

    Your application must still prevent duplicate triggers.
  </Accordion>

  <Accordion title="How is an order total calculated?">
    The SDK uses `order.total` when it is a finite number. Otherwise, it calculates the total from each price and quantity in `order.products`.

    Zero is a valid total, tax, discount, or shipping value.
  </Accordion>

  <Accordion title="Why are top-level products missing from an order event?">
    When a payload contains `order`, put its items in `order.products`. Top-level `products` do not replace missing `order.products` for that event.
  </Accordion>

  <Accordion title="Can custom properties contain any value?">
    The type accepts additional top-level properties. In production, use stable, JSON-serializable values with reviewed meaning and data classification.

    Never pass raw errors, request objects, secrets, or unredacted user content.
  </Accordion>

  <Accordion title="How should I change an event contract after release?">
    Prefer additive changes. Add a new property before you remove an old one, and keep property types stable.

    Create a new event name when the business meaning changes. Validate the migration in staging and update the event catalog.
  </Accordion>
</AccordionGroup>

## Keep identity and attribution in scope

<AccordionGroup>
  <Accordion title="What is the Bily browser tracking ID?">
    `getBilyTrackingId()` returns an identifier for the current browser context. The SDK keeps it stable in browser storage when possible.

    It is not a password, authenticated user ID, or authorization value.
  </Accordion>

  <Accordion title="What happens when browser storage is cleared or blocked?">
    Clearing browser storage can give a later browser context a new ID. If storage is blocked, the SDK can keep an in-memory identifier stable for the current page session.
  </Accordion>

  <Accordion title="How do I attach an authenticated user ID?">
    Add your stable internal account ID as `client.userId` only to events that need authenticated customer context and that your consent policy allows.
  </Accordion>

  <Accordion title="Does client.userId merge anonymous and known identities?">
    No. The public SDK does not expose an identity-merge command or promise a merge from `client.userId`.

    Treat the value as context for that event. Do not describe matching email or user fields as an automatic merge.
  </Accordion>

  <Accordion title="Does Bily share a browser ID across domains?">
    No. The public SDK does not define cross-domain browser-ID sharing.

    Treat each browser origin as its own storage boundary unless a separate verified Bily contract says otherwise.
  </Accordion>

  <Accordion title="Does the SDK automatically define first-touch or last-touch attribution?">
    No. The public SDK accepts page, referrer, and custom campaign context, but it does not define a first-touch or last-touch rule.

    Use the fields returned by Bily analytics operations as the reporting contract. Verify the output required for your business decision.
  </Accordion>

  <Accordion title="Which acquisition fields can I send?">
    Use `sourceUrl`, `pageTitle`, and `referrer` for page context. Add reviewed custom properties for campaign or channel IDs.

    Remove sensitive query values. Never include credentials or session data.
  </Accordion>
</AccordionGroup>

## Read analytics consistently

<AccordionGroup>
  <Accordion title="What do conversions, people, sessions, and pageviews mean?">
    In Bily advertising analytics, `conversions` means orders. `people` means unique browser visitors. `sessions` means total 30-minute visits. `pageviews` means tracked page-view events.

    Keep these labels distinct.
  </Accordion>

  <Accordion title="How should I calculate conversion rate?">
    Choose and name a complete traffic denominator. Visitor CVR is `sum(conversions) / sum(people)`. Session CVR is `sum(conversions) / sum(sessions)`.

    Multiply the ratio by 100 only when you present it as a percentage.

    Do not divide by orders, revenue, customers, purchase-only sessions, or rows already filtered to conversions. Those values exclude traffic that did not purchase.
  </Accordion>

  <Accordion title="Why can’t I add platform spend across currencies?">
    Raw platform money such as `p_spend` remains in each ad account's native `p_currency`. Group raw aggregates by currency.

    Use Bily's normalized channel or asset reports for store-currency spend and cross-account efficiency metrics.
  </Accordion>

  <Accordion title="What is the difference between product orders and units?">
    Product orders count product-order occurrences. Units count product quantity.

    In `product_metrics`, use `sum(orders)` for product orders and `sum(units)` for units. Do not use the row count for either metric.
  </Accordion>

  <Accordion title="How does Bily define ROAS, CPA, and CAC?">
    In normalized Bily reports, ROAS is revenue divided by spend. CPA is spend divided by orders. CAC is spend divided by customers.

    A metric is unavailable when its denominator is zero. CPA and CAC differ when one customer can place several orders.
  </Accordion>

  <Accordion title="How does Bily define LTV?">
    The `customer_ltv` dataset defines LTV as a customer's total lifetime revenue. Average LTV averages customer `total_revenue`. Net LTV subtracts refunds where available.

    Do not label this lifetime dataset as period new-versus-returning revenue.
  </Accordion>

  <Accordion title="What is data readiness?">
    Data readiness shows the connector and account-selection status for each platform in a store. Use it to see whether you need to connect a source, select accounts, or wait for more data.
  </Accordion>

  <Accordion title="What does a quality warning mean?">
    A quality warning explains why an analytics result needs review. It can include a code, severity, message, evidence, and recommended next step.

    Resolve blocking warnings and `review_required` results before making channel, budget, creative, or attribution decisions.
  </Accordion>

  <Accordion title="What are connections, pixels, ad accounts, and assets?">
    A connection links a store to a supported data or activation surface. A pixel is the public API resource for a store-scoped tracking connection.

    An ad account is an advertising account mapped to the store. An asset is a normalized campaign, ad set, or ad inside an enabled account.

    The [glossary](/concepts/glossary) defines each term's fields and boundaries.
  </Accordion>
</AccordionGroup>

## Choose and operate the API or MCP

<AccordionGroup>
  <Accordion title="When should I use the Bily API?">
    Use the API when trusted server code owns a deterministic, repeatable workflow. Good fits include scheduled jobs, internal services, typed OpenAPI clients, scoped analytics reads, and explicit supported actions.
  </Accordion>

  <Accordion title="Can I call the Bily API from browser JavaScript?">
    No. Keep Bily API keys out of browser code and client-visible environment variables.

    Call the API from a trusted server. Apply your own application authorization before returning data to a browser.
  </Accordion>

  <Accordion title="How do I discover my organization and store?">
    Call `GET /context`. It returns the authenticated user and accessible organizations, with stores nested under each organization.

    A standard store-scoped key needs no parameter. Copy the exact returned `organizations[].stores[].url` into store-scoped paths.
  </Accordion>

  <Accordion title="Is a Bily API key store-scoped?">
    Yes. A key created while a store is selected carries that store and its organization as its API scope.

    Select the intended store before creating the key under **Settings > MCP > Access key fallback**. Bily then rejects requests for another store or organization.
  </Accordion>

  <Accordion title="Why does my older fallback key require store scope?">
    Older settings-generated keys may lack the store and organization required by current API and MCP boundaries.

    Select the intended store and create a replacement under **Settings > MCP > Access key fallback**. Update the workload, verify `GET /context` or `bily.context()`, then revoke the older key.
  </Accordion>

  <Accordion title="What is the difference between 401 and 403?">
    A `401` means the credential is missing, invalid, expired, or revoked. Reconnect or replace it.

    A `403` means the caller is authenticated but lacks the required permission, organization access, store scope, or action access. Confirm the requested scope.
  </Accordion>

  <Accordion title="Should I retry a failed API request?">
    Retry safe reads after transient `429`, `500`, `502`, or `504` responses. Use capped exponential backoff with jitter.

    Do not automatically retry a write until a read shows whether the first attempt took effect.
  </Accordion>

  <Accordion title="Why does Bily MCP expose only two tools?">
    `search` discovers the current operation catalog at runtime. `execute` runs the selected `bily.*` helpers.

    This two-tool model keeps the top-level client contract stable as Bily operations evolve.
  </Accordion>

  <Accordion title="Does MCP enforce a human approval step?">
    No. Bily returns advisory risk, approval, precondition, verification, and rollback guidance.

    The AI client must keep its approval prompt visible and show the complete `execute` function. Planning metadata alone does not prove human approval.
  </Accordion>

  <Accordion title="What can execute() run?">
    It runs a focused async arrow function of at most 20,000 characters for up to 20 seconds. The function uses `bily.*` helpers and has no direct outbound network access.

    It returns JSON-serializable `result` data with captured `logs`.
  </Accordion>

  <Accordion title="What is the difference between Bily Connect and a fallback key?">
    Bily Connect uses the signed-in user's current Bily organization and store memberships.

    A fallback key is for clients that cannot complete sign-in. It carries the selected default store and organization scope in MCP.
  </Accordion>

  <Accordion title="Why did Bily Connect ask me to sign in again?">
    Reconnect through Bily Connect. Bily rotates refresh credentials for security.

    Reusing an older refresh credential or losing the latest refresh response can invalidate the connection. Do not keep retrying an older credential.
  </Accordion>

  <Accordion title="Are llms.txt and llms-full.txt MCP endpoints?">
    No. They are agent-readable documentation resources at `docs.bily.ai`.

    Use `https://api-dispatcher.bily.ai/mcp` as the MCP endpoint.
  </Accordion>
</AccordionGroup>

## Protect data and release with confidence

<AccordionGroup>
  <Accordion title="Can I send email, phone, or address data?">
    The typed `client` object accepts these optional fields. Type support does not grant permission to collect them.

    Send only fields with a documented purpose, consent basis, and retention decision.
  </Accordion>

  <Accordion title="What data must never be sent in a browser event?">
    Never send passwords, session values, authorization headers, access or refresh tokens, or private API keys.

    Also keep payment-card or bank details, private message bodies, raw form submissions, raw errors, request bodies, and stack traces out of browser events.
  </Accordion>

  <Accordion title="Does the SDK manage consent for my application?">
    No. Your application must decide whether an event or customer field is allowed before it calls `track()`.

    Test consent-not-selected, accepted, denied, changed, signed-out, and signed-in states.
  </Accordion>

  <Accordion title="Why can’t I see an event even though ready() resolved?">
    `ready()` verifies loading, not ingestion.

    Confirm that the successful product path reached `track()` once. Check that the event name is non-empty, the page uses the intended tracking URL, consent allows the call, and the observed payload matches the event plan.
  </Accordion>

  <Accordion title="Why do I see duplicate page views?">
    Common causes include installing both the raw script and SDK, sending a manual initial `PageView`, registering several router listeners, or failing to deduplicate the current URL.

    Keep one script and one page-view owner.
  </Accordion>

  <Accordion title="Why are early events missing?">
    Make sure the application eventually calls `init()`. Then check whether high-volume startup calls filled the bounded queue.

    When the queue reaches `maxQueueSize`, the SDK discards the oldest call.
  </Accordion>

  <Accordion title="How should I validate a production release?">
    Begin with limited exposure. Verify one script and representative events across signed-out, signed-in, and consent states.

    Exercise safe API and MCP reads. Expand only after the observed result matches the reviewed contract.

    Follow [Production rollout](/guides/production-rollout) for the complete sequence.
  </Accordion>

  <Accordion title="What should I send to Bily support?">
    Send the environment, selected store, SDK or client version, safe event or operation name, expected and observed result, reproduction steps, timestamp, and Bily request ID when available.

    Remove credentials, customer payloads, session data, and full request headers.
  </Accordion>
</AccordionGroup>

<CardGroup cols={2}>
  <Card title="Validation and debugging" icon="list-check" href="/guides/validation-debugging" />

  <Card title="Bily glossary" icon="book" href="/concepts/glossary" />
</CardGroup>
