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

# Quickstart

> Track your LLM calls, join them to your revenue, and start optimising, in 5 minutes.

<Steps titleSize="h3">
  <Step title="Get your API key">
    Create an API key in the Weflayr Dashboard. Either expose it as the `WEFLAYR_API_KEY` environment variable, or pass it directly to `autoInstrument()` in the next step.

    ```bash .env theme={null}
    WEFLAYR_API_KEY=your-api-key
    ```
  </Step>

  <Step title="Install and instrument">
    Choose your AI provider SDK you are using & follow the install commands. Then run the auto instrumentation command as shown.
    PS: This works regardless of the Framework you are using (Langchain, Mastra, etc...)

    <Tabs>
      <Tab title="Anthropic" icon="https://www.google.com/s2/favicons?domain=anthropic.com&sz=64">
        **Install:**

        <CodeGroup>
          ```js Node.js theme={null}
          npm install weflayr @anthropic-ai/sdk @traceloop/instrumentation-anthropic
          ```

          ```python Python theme={null}
          pip install weflayr anthropic opentelemetry-instrumentation-anthropic
          ```
        </CodeGroup>

        **Instrument:**

        <CodeGroup>
          ```js Node.js theme={null}
          const weflayr = require('weflayr');

          await weflayr.autoInstrument({ aiSdks: 'anthropic' });
          ```

          ```python Python theme={null}
          import weflayr

          weflayr.auto_instrument(ai_sdks=weflayr.AiSdk.ANTHROPIC)
          ```
        </CodeGroup>
      </Tab>

      <Tab title="OpenAI" icon="https://www.google.com/s2/favicons?domain=openai.com&sz=64">
        **Install:**

        <CodeGroup>
          ```js Node.js theme={null}
          npm install weflayr openai @traceloop/instrumentation-openai
          ```

          ```python Python theme={null}
          pip install weflayr openai opentelemetry-instrumentation-openai
          ```
        </CodeGroup>

        **Instrument:**

        <CodeGroup>
          ```js Node.js theme={null}
          const weflayr = require('weflayr');

          await weflayr.autoInstrument({ aiSdks: 'openai' });
          ```

          ```python Python theme={null}
          import weflayr

          weflayr.auto_instrument(ai_sdks=weflayr.AiSdk.OPENAI)
          ```
        </CodeGroup>

        <Warning>
          **Streaming with the OpenAI SDK directly?** OpenAI only returns token usage on streamed responses when you ask for it. Pass `stream_options` with `include_usage` on streaming calls, otherwise the prompt/completion token counts (and cost) will be missing from those spans.

          <CodeGroup>
            ```js Node.js theme={null}
            await client.chat.completions.create({
              model: 'gpt-5.5',
              messages: [{ role: 'user', content: 'Hello!' }],
              stream: true,
              stream_options: { include_usage: true },
            });
            ```

            ```python Python theme={null}
            client.chat.completions.create(
                model="gpt-5.5",
                messages=[{"role": "user", "content": "Hello!"}],
                stream=True,
                stream_options={"include_usage": True},
            )
            ```
          </CodeGroup>
        </Warning>
      </Tab>

      <Tab title="AWS Bedrock" icon="https://www.google.com/s2/favicons?domain=aws.amazon.com&sz=64">
        **Install:**

        <CodeGroup>
          ```js Node.js theme={null}
          npm install weflayr @aws-sdk/client-bedrock-runtime @traceloop/instrumentation-bedrock
          ```

          ```python Python theme={null}
          pip install weflayr boto3 opentelemetry-instrumentation-bedrock
          ```
        </CodeGroup>

        **Instrument:**

        <CodeGroup>
          ```js Node.js theme={null}
          const weflayr = require('weflayr');

          await weflayr.autoInstrument({ aiSdks: 'bedrock' });
          ```

          ```python Python theme={null}
          import weflayr

          weflayr.auto_instrument(ai_sdks=weflayr.AiSdk.BEDROCK)
          ```
        </CodeGroup>
      </Tab>

      <Tab title="Google GenAI" icon="https://www.google.com/s2/favicons?domain=ai.google.dev&sz=64">
        **Install:**

        <CodeGroup>
          ```js Node.js theme={null}
          npm install weflayr @google/genai @traceloop/instrumentation-google-generativeai
          ```

          ```python Python theme={null}
          pip install weflayr google-genai opentelemetry-instrumentation-google-genai
          ```
        </CodeGroup>

        **Instrument:**

        <CodeGroup>
          ```js Node.js theme={null}
          const weflayr = require('weflayr');

          await weflayr.autoInstrument({ aiSdks: 'google-genai' });
          ```

          ```python Python theme={null}
          import weflayr

          weflayr.auto_instrument(ai_sdks=weflayr.AiSdk.GOOGLE_GENAI)
          ```
        </CodeGroup>
      </Tab>

      <Tab title="Other">
        <AccordionGroup>
          <Accordion title="Azure OpenAI" icon="https://www.google.com/s2/favicons?domain=portal.azure.com&sz=64">
            Use Azure OpenAI through the OpenAI SDK. Weflayr auto-detects the Azure endpoint.

            **Install:**

            <CodeGroup>
              ```js Node.js theme={null}
              npm install weflayr openai @traceloop/instrumentation-openai
              ```

              ```python Python theme={null}
              pip install weflayr openai opentelemetry-instrumentation-openai
              ```
            </CodeGroup>

            **Instrument:**

            <CodeGroup>
              ```js Node.js theme={null}
              await weflayr.autoInstrument({ aiSdks: 'openai' });

              const { AzureOpenAI } = require('openai');
              const client = new AzureOpenAI({
                endpoint: process.env.AZURE_OPENAI_ENDPOINT,
                apiKey: process.env.AZURE_OPENAI_API_KEY,
                apiVersion: '2024-10-21',
              });

              await client.chat.completions.create({
                model: 'your-deployment',
                messages: [{ role: 'user', content: 'Hello!' }],
              });
              ```

              ```python Python theme={null}
              weflayr.auto_instrument(ai_sdks=weflayr.AiSdk.OPENAI)

              from openai import AzureOpenAI

              client = AzureOpenAI(
                  azure_endpoint=os.environ["AZURE_OPENAI_ENDPOINT"],
                  api_key=os.environ["AZURE_OPENAI_API_KEY"],
                  api_version="2024-10-21",
              )

              client.chat.completions.create(
                  model="your-deployment",
                  messages=[{"role": "user", "content": "Hello!"}],
              )
              ```
            </CodeGroup>
          </Accordion>

          <Accordion title="Cohere" icon="https://www.google.com/s2/favicons?domain=cohere.com&sz=64">
            **Install:**

            <CodeGroup>
              ```js Node.js theme={null}
              npm install weflayr cohere-ai @traceloop/instrumentation-cohere
              ```

              ```python Python theme={null}
              pip install weflayr cohere opentelemetry-instrumentation-cohere
              ```
            </CodeGroup>

            **Instrument:**

            <CodeGroup>
              ```js Node.js theme={null}
              await weflayr.autoInstrument({ aiSdks: 'cohere' });
              ```

              ```python Python theme={null}
              weflayr.auto_instrument(ai_sdks=weflayr.AiSdk.COHERE)
              ```
            </CodeGroup>
          </Accordion>

          <Accordion title="ElevenLabs" icon="https://www.google.com/s2/favicons?domain=elevenlabs.io&sz=64">
            **Install:**

            <CodeGroup>
              ```js Node.js theme={null}
              npm install weflayr @elevenlabs/elevenlabs-js
              ```

              ```python Python theme={null}
              pip install weflayr elevenlabs
              ```
            </CodeGroup>

            **Instrument:**

            <CodeGroup>
              ```js Node.js theme={null}
              await weflayr.autoInstrument({ aiSdks: 'elevenlabs' });
              ```

              ```python Python theme={null}
              weflayr.auto_instrument(ai_sdks=weflayr.AiSdk.ELEVENLABS)
              ```
            </CodeGroup>
          </Accordion>

          <Accordion title="Mistral AI" icon="https://www.google.com/s2/favicons?domain=mistral.ai&sz=64">
            <Tabs>
              <Tab title="Node.js">
                Mistral models are called through the OpenAI SDK, so instrument OpenAI and pass `providerNameOverride: weflayr.AIProviderName.MISTRAL` to `propagateMetadata()`.
              </Tab>

              <Tab title="Python">
                Instrument the Mistral SDK directly.
              </Tab>
            </Tabs>

            **Install:**

            <CodeGroup>
              ```js Node.js theme={null}
              npm install weflayr openai @traceloop/instrumentation-openai
              ```

              ```python Python theme={null}
              pip install weflayr mistralai
              ```
            </CodeGroup>

            **Instrument:**

            <CodeGroup>
              ```js Node.js theme={null}
              await weflayr.autoInstrument({ aiSdks: 'openai' });

              const OpenAI = require('openai');
              const client = new OpenAI({
                baseURL: 'https://api.mistral.ai/v1',
                apiKey: process.env.MISTRAL_API_KEY,
              });

              await weflayr.propagateMetadata(
                { featureName: 'support-chat', customerId: 'c_123', providerNameOverride: weflayr.AIProviderName.MISTRAL },
                async () => {
                  await client.chat.completions.create({
                    model: 'mistral-small-latest',
                    messages: [{ role: 'user', content: 'Hello!' }],
                  });
                }
              );
              ```

              ```python Python theme={null}
              weflayr.auto_instrument(ai_sdks=weflayr.AiSdk.MISTRAL)
              ```
            </CodeGroup>
          </Accordion>

          <Accordion title="Vercel AI SDK" icon="https://www.google.com/s2/favicons?domain=vercel.com&sz=64">
            <Tabs>
              <Tab title="Node.js">
                Weflayr instruments the Vercel AI SDK natively. Calls through a provider package with your own key (e.g. `@ai-sdk/openai`) are attributed to that provider and priced at its rates.
              </Tab>

              <Tab title="Python">
                Call Vercel through the OpenAI SDK and label the calls with `provider_name_override=weflayr.AIProviderName.VERCEL_AI_GATEWAY` in `propagate_metadata`.
              </Tab>
            </Tabs>

            Vercel adds a markup of \~3% when buying credits (small variations depending how much tokens you buy). Weflayr therefore prices gateway calls at the model price listed by the gateway plus 3%.

            <Tabs>
              <Tab title="ai v7">
                **Install:**

                <CodeGroup>
                  ```js Node.js theme={null}
                  npm install weflayr ai @ai-sdk/otel
                  ```

                  ```python Python theme={null}
                  pip install weflayr openai opentelemetry-instrumentation-openai
                  ```
                </CodeGroup>

                **Instrument:**

                <CodeGroup>
                  ```js Node.js theme={null}
                  await weflayr.autoInstrument({ aiSdks: 'vercel_ai_gateway' });

                  const { generateText } = require('ai');

                  // AI Gateway (default): plain "creator/model" string, key in AI_GATEWAY_API_KEY.
                  await weflayr.propagateMetadata(
                    { featureName: 'support-chat', customerName: 'Acme Corp' },
                    async () => {
                      await generateText({
                        model: 'anthropic/claude-sonnet-4.5',
                        prompt: 'Hello!',
                      });
                    }
                  );

                  // Provider package with your own key: the call is automatically attributed
                  // to that provider (openai here) and priced at its rates.
                  const { createOpenAI } = require('@ai-sdk/openai');
                  const openai = createOpenAI({ apiKey: process.env.OPENAI_API_KEY });

                  await weflayr.propagateMetadata(
                    { featureName: 'support-chat', customerName: 'Acme Corp' },
                    async () => {
                      await generateText({ model: openai('gpt-5.4'), prompt: 'Hello!' });
                    }
                  );
                  ```

                  ```python Python theme={null}
                  weflayr.auto_instrument(ai_sdks=weflayr.AiSdk.OPENAI)

                  from openai import OpenAI

                  client = OpenAI(
                      base_url="https://ai-gateway.vercel.sh/v1",
                      api_key=os.environ["AI_GATEWAY_API_KEY"],
                  )

                  with weflayr.propagate_metadata(
                      feature_name="support-chat",
                      customer_name="Acme Corp",
                      provider_name_override=weflayr.AIProviderName.VERCEL_AI_GATEWAY,
                  ):
                      client.chat.completions.create(
                          model="anthropic/claude-sonnet-4.5",
                          messages=[{"role": "user", "content": "Hello!"}],
                      )
                  ```
                </CodeGroup>
              </Tab>

              <Tab title="ai v5 / v6">
                <Tabs>
                  <Tab title="Node.js">
                    Autoinstrument without specifying any SDK, and make sure `experimental_telemetry: { isEnabled: true }` is passed on each Vercel call to allow the spans to be picked up by Weflayr's tracer.
                  </Tab>

                  <Tab title="Python">
                    Nothing changes between `ai` versions: Vercel is reached through the OpenAI SDK either way.
                  </Tab>
                </Tabs>

                **Install:**

                <CodeGroup>
                  ```js Node.js theme={null}
                  npm install weflayr ai
                  ```

                  ```python Python theme={null}
                  pip install weflayr openai opentelemetry-instrumentation-openai
                  ```
                </CodeGroup>

                **Instrument:**

                <CodeGroup>
                  ```js Node.js theme={null}
                  await weflayr.autoInstrument({ aiSdks: [] });

                  const { generateText } = require('ai');

                  // AI Gateway (default): plain "creator/model" string, key in AI_GATEWAY_API_KEY.
                  await weflayr.propagateMetadata(
                    { featureName: 'support-chat', customerName: 'Acme Corp' },
                    async () => {
                      await generateText({
                        model: 'anthropic/claude-sonnet-4.5',
                        prompt: 'Hello!',
                        experimental_telemetry: { isEnabled: true },
                      });
                    }
                  );

                  // Provider package with your own key: the call is automatically attributed
                  // to that provider (openai here) and priced at its rates.
                  const { createOpenAI } = require('@ai-sdk/openai');
                  const openai = createOpenAI({ apiKey: process.env.OPENAI_API_KEY });

                  await weflayr.propagateMetadata(
                    { featureName: 'support-chat', customerName: 'Acme Corp' },
                    async () => {
                      await generateText({
                        model: openai('gpt-5.4'),
                        prompt: 'Hello!',
                        experimental_telemetry: { isEnabled: true },
                      });
                    }
                  );
                  ```

                  ```python Python theme={null}
                  weflayr.auto_instrument(ai_sdks=weflayr.AiSdk.OPENAI)

                  from openai import OpenAI

                  client = OpenAI(
                      base_url="https://ai-gateway.vercel.sh/v1",
                      api_key=os.environ["AI_GATEWAY_API_KEY"],
                  )

                  with weflayr.propagate_metadata(
                      feature_name="support-chat",
                      customer_name="Acme Corp",
                      provider_name_override=weflayr.AIProviderName.VERCEL_AI_GATEWAY,
                  ):
                      client.chat.completions.create(
                          model="anthropic/claude-sonnet-4.5",
                          messages=[{"role": "user", "content": "Hello!"}],
                      )
                  ```
                </CodeGroup>
              </Tab>
            </Tabs>
          </Accordion>
        </AccordionGroup>
      </Tab>
    </Tabs>

    <Accordion title="All parameters for autoInstrument() / auto_instrument()">
      <ParamField body="aiSdks / ai_sdks" type="string, enum member, or a list of them" required>
        <Tabs>
          <Tab title="Node.js">
            `'openai'`, `'anthropic'`, `'bedrock'`, `'cohere'`, `'google-genai'`, `'elevenlabs'`, or an array of them.
          </Tab>

          <Tab title="Python">
            A `weflayr.AiSdk` enum member (`OPENAI`, `ANTHROPIC`, `BEDROCK`, `COHERE`, `GOOGLE_GENAI`, `ELEVENLABS`, `MISTRAL`), or an iterable of them.
          </Tab>
        </Tabs>

        Each value picks the matching OpenTelemetry instrumentation package to load. Install the package separately.
      </ParamField>

      <ParamField body="apiKey / api_key" type="string">
        Defaults to the `WEFLAYR_API_KEY` environment variable. Pass explicitly to override.
      </ParamField>

      <ParamField body="defaultTags / default_tags" type="object">
        Tags stamped on every emitted span.
      </ParamField>

      <ParamField body="exportMode / export_mode" type="&#x22;batch&#x22; | &#x22;immediate&#x22;" default="&#x22;batch&#x22;">
        Use `"immediate"` to export telemetry after every call.
      </ParamField>

      <ParamField body="captureMessageContent / capture_message_content" type="boolean" default="true">
        Set `false` to strip `gen_ai.prompt` / `gen_ai.completion` from spans before export.
      </ParamField>

      <ParamField body="mask" type="function">
        Redact or rewrite fields before they leave your process. See the mask example below.
      </ParamField>

      <ParamField body="warnOnExportError / warn_on_export_error" type="boolean" default="true">
        Set `false` to silence the one-shot stderr warning emitted on the first export failure.
      </ParamField>

      #### Mask example

      Use `mask` to redact PII (emails, credit cards, customer names) or to drop entire prompts before they're sent to Weflayr. Your callback runs on a copy of the span attributes right before export; whatever you return is what we store. Return `null` to drop the span entirely.

      <CodeGroup>
        ```js Node.js theme={null}
        await weflayr.autoInstrument({
          aiSdks: 'openai',
          mask: (attrs) => {
            // Strip emails out of the prompt
            if (typeof attrs['gen_ai.prompt'] === 'string') {
              attrs['gen_ai.prompt'] = attrs['gen_ai.prompt'].replace(
                /[\w.+-]+@[\w-]+\.[\w.-]+/g,
                '[email]'
              );
            }
            return attrs;
          },
        });
        ```

        ```python Python theme={null}
        import re

        def mask(attrs):
            prompt = attrs.get("gen_ai.prompt")
            if isinstance(prompt, str):
                attrs["gen_ai.prompt"] = re.sub(r"[\w.+-]+@[\w-]+\.[\w.-]+", "[email]", prompt)
            return attrs

        weflayr.auto_instrument(ai_sdks=weflayr.AiSdk.OPENAI, mask=mask)
        ```
      </CodeGroup>
    </Accordion>
  </Step>

  <Step title="Add metadata to your LLM calls for finer analysis">
    Wrap your LLM calls in `propagateMetadata` / `propagate_metadata` to stamp each emitted span with **who** the call is for (`customer_name`) and **why** it's happening (`feature_name`). Anything inside the scope, including nested calls, picks up the same metadata.

    <Note>
      Tagging `feature_name` and `customer_name` unlock per-customer and per-feature breakdowns across the dashboard, for analysis (e.g. [margin](/product/margin)) and for benchmarking (e.g. [model benchmark](/product/model-benchmark)).
    </Note>

    **As a callback / context manager**

    Wrap a single block of code. Every LLM call made inside picks up the metadata.

    <CodeGroup>
      ```js Node.js theme={null}
      await weflayr.propagateMetadata(
        { featureName: 'support-chat', customerName: 'Acme Corp' },
        async () => {
          // Any LLM call made here gets feature_name + customer_name stamped on its span.
          await client.chat.completions.create({ ... });
        }
      );
      ```

      ```python Python theme={null}
      with weflayr.propagate_metadata(feature_name="support-chat", customer_name="Acme Corp"):
          # Any LLM call made here gets feature_name + customer_name stamped on its span.
          client.chat.completions.create(...)
      ```
    </CodeGroup>

    **As a decorator**

    Apply once to a function or method, and every call automatically picks up the metadata.

    <CodeGroup>
      ```js Node.js theme={null}
      class ChatService {
        @weflayr.propagateMetadata({ featureName: 'support-chat', customerName: 'Acme Corp' })
        async reply() {
          await client.chat.completions.create({ ... });
        }
      }
      ```

      ```python Python theme={null}
      @weflayr.propagate_metadata(feature_name="support-chat", customer_name="Acme Corp")
      def reply():
          client.chat.completions.create(...)
      ```
    </CodeGroup>

    <Accordion title="All parameters for propagateMetadata() / propagate_metadata()">
      <ParamField body="featureName / feature_name" type="string" required>
        The product-side feature triggering the LLM call (e.g. `"support-chat"`, `"onboarding-summary"`).
      </ParamField>

      <ParamField body="customerName / customer_name" type="string" required>
        Name of the end-user or tenant customer the call is made for.
      </ParamField>

      <ParamField body="providerNameOverride / provider_name_override" type="enum member">
        Override the auto-detected provider. Use this when the SDK on the wire differs from the provider to bill (e.g. Mistral or the Vercel AI Gateway reached through the OpenAI SDK).
      </ParamField>

      <ParamField body="extraTags / extra_tags" type="object">
        Any scalar key/value pairs (string / number / boolean) that you may need to analyse your costs in more detail.
      </ParamField>
    </Accordion>
  </Step>

  <Step title="Flush before exit (short-lived runtimes only)">
    In long-running servers, spans are flushed automatically. In short-lived runtimes (Lambda, scripts, edge functions), call `flush()` before exit so the final spans reach Weflayr.

    <CodeGroup>
      ```js Node.js theme={null}
      await weflayr.flush();
      ```

      ```python Python theme={null}
      weflayr.flush()
      ```
    </CodeGroup>
  </Step>

  <Step title="Set up your revenue tracking">
    Bring your revenue in from **Costs & revenue** in the dashboard sidebar (connect Stripe or upload a CSV) or push it with the [Revenue API](/api/revenue). See [Sync Revenue](/configure/sync-revenue) for the three options.

    Revenue lands on the same customer as your AI cost through the `customer_name` you stamped on your calls in the previous step.
  </Step>

  <Step title="Observe your margin and optimise your AI costs">
    Your calls now stream to the dashboard and can be optimised: see the [platform documentation](/product)
  </Step>
</Steps>

## Implementation examples

<Columns cols={2}>
  <Card title="Multiple AI providers" icon="layer-group" href="/examples/multi-provider">
    A single app that calls both OpenAI and Anthropic.
  </Card>

  <Card title="AI Framework" icon="diagram-project" href="/examples/ai-framework">
    Every call your framework's chain makes, captured.
  </Card>
</Columns>
