monetzly
My knees hurt after a run
Ice them, then try Recovery Gel
↑ contextual placement · sponsored
Weaving ads into the conversation…
monetzly
ProductHow it WorksPricing
Login
Join waitlist
  1. Home
  2. Docs

Documentation

Monetzly server SDK quickstart

Applies to @monetzly/server-sdk v1.x · Node 18+

Monetzly sits between your model and your client. You keep generating responses exactly as you do today; the SDK reads the response stream, decides whether any campaign genuinely matches the conversation, and injects a labelled sponsored mention when one does.

The integration is one wrapper around an existing stream. Most apps are done in under an hour, including the failure-path work.

On this page

  • 1. Install
  • 2. Configure the client
  • 3. Wrap your response stream
  • 4. Non-streaming responses
  • 5. Fail open, always
  • 6. Controls you own
  • 7. Launch checklist
  • Framework-specific guides

1. Install

npm install @monetzly/server-sdk

The package is server-side only. It talks to the Monetzly ad service over gRPC and holds your API key, so it must never be bundled into client code.

Access: API keys are issued during onboarding while Monetzly is in private access. Join the waitlist or book a call and we will provision a key and a server address for you.

2. Configure the client

Create the client once at module scope so the connection is reused across requests, rather than per invocation.

import { MonetzlySDK, MonetzlyConfig } from "@monetzly/server-sdk";

const config: MonetzlyConfig = {
  apiKey: process.env.MONETZLY_API_KEY!,
  serverAddress: process.env.MONETZLY_SERVER_ADDRESS!, // host:port
  useSSL: true,
  timeout: 30000,
};

export const sdk = new MonetzlySDK(config);
OptionTypeNotes
apiKeystring (required)Issued during onboarding. Read it from the environment; never commit it.
serverAddressstring (required)host:port of the ad service. Use localhost:8080 with useSSL: false for local development.
useSSLbooleanTLS to the ad service. Always true outside local development.
timeoutnumber (ms)Per-call budget. Keep it well under your own response deadline.
metadataRecord<string, string>Static key/value pairs attached to every call — useful for tagging an app or environment.

Environment variables

MONETZLY_API_KEY=mz_live_...
MONETZLY_SERVER_ADDRESS=ads.monetzly.com:443

3. Wrap your response stream

Call connect() before the first injection, then pass your model's token stream through inject(). It accepts an AsyncIterable or a ReadableStream of chunks and returns an async generator of the same chunk shape, so your existing forwarding loop is unchanged.

await sdk.connect();

const llmStream = await llm.stream(messages);

for await (const chunk of sdk.inject(llmStream, {
  sessionId,                          // stable per conversation
  metadata: { app: "my-assistant" },  // optional, per-call
})) {
  const text = chunk.text ?? chunk.content ?? "";
  if (text) controller.enqueue(encoder.encode(text));
}
InjectParamsTypeNotes
sessionIdstringTies impressions and clicks to one conversation. Pass a stable id per session, not a per-request uuid. Generated for you if omitted.
promptstringOptional user prompt for the turn, used to sharpen context matching.
metadataRecord<string, string>Per-call tags, merged over the client-level metadata.
No match is the normal case. When nothing qualifies, chunks pass through unchanged and the user sees exactly what your model produced. A low fill rate is the intended behaviour, not a misconfiguration.

4. Non-streaming responses

If your endpoint returns a single completion rather than a stream, wrap the completion in a one-chunk async iterable and concatenate the result.

async function* once(text: string) {
  yield { text };
}

let out = "";
for await (const chunk of sdk.inject(once(completion.text), { sessionId })) {
  out += chunk.text ?? chunk.content ?? "";
}
return out;

5. Fail open, always

Monetization must never be able to break the product. Treat the ad layer as optional and fall back to the unmodified stream on any error.

let stream: AsyncIterable<{ text?: string; content?: string }> = llmStream;
try {
  await sdk.connect();
  stream = sdk.inject(llmStream, { sessionId });
} catch (err) {
  console.error("monetzly unavailable — streaming unmodified response", err);
}

for await (const chunk of stream) {
  /* forward exactly as before */
}
  • Keep timeout tight relative to your own latency budget, so a slow match can never delay the first token.
  • Log fallbacks with a counter you can alert on — silent degradation looks like zero revenue with no cause.
  • isConfigured() tells you whether the client has usable credentials; use it to skip injection entirely in environments without a key.

6. Controls you own

  • Category blocks — exclude competitors, regulated goods, or anything off-brand. Configured per app during onboarding.
  • Sensitive-context suppression — health, finance, legal and anything involving minors default to no placements.
  • Frequency caps — placements per session are capped independently of how many turns would technically qualify.
  • Per-turn suppression — skip injection on turns where advice quality matters more than revenue by streaming the original stream directly.

Sponsored elements are always labelled as sponsored in the response. That is not configurable, and it is what keeps the format viable.

7. Launch checklist

  1. A conversation with clear commercial intent produces a labelled sponsored mention.
  2. A conversation with none produces a response byte-identical to the unwrapped version.
  3. With the ad service unreachable, responses still stream normally.
  4. Impressions and clicks appear against the sessionId you passed.
  5. Your API key is absent from client bundles (grep the build output).
  6. Category blocks and sensitive-context rules match what your app actually serves.

Framework-specific guides

Integration guides by frameworkLangChain, Vercel AI SDK, FastAPI, LlamaIndex and more.How-to recipesTask-level walkthroughs: streaming, session ids, testing, attribution.Streaming walkthroughThe same integration written up end to end, with the failure path.GlossaryFill rate, eCPM, ad injection, session attribution — defined.

Need a key, or a second pair of eyes on the integration?

Monetzly is in private access. Join the waitlist for a key, or book time and we will walk through your stack with you.

Join the waitlistBook a call

Related

Changelog
Status
Live demo
monetzly

Monetization for AI-native apps.

PRODUCT
OverviewHow it WorksUse CasesPricingFor Advertisers
RESOURCES
DocsGuidesFree ToolsChangelogStatus
COMPANY
AboutBlogContact
SOCIAL
Twitter / XLinkedIn
© 2026 Monetzly, Inc. All rights reserved.