← Back to Patterns

Embed Companion in Proxy Mode

Availablecompanionintermediate

Overview

Deploy a Companion widget on any website with the delegation token held server-side. The browser never sees the token — only the deployment_id and surface_context travel in the request.

When to use

  • Public-facing websites where you cannot expose credentials in HTML
  • Customer portals, developer docs, support sites
  • Any deployment where you need origin validation (CORS whitelist per deployment)
  • Prerequisites

  • A companion_deployments record with a minted delegation token
  • A proxy endpoint on your host server (/api/companion/ask)
  • Create the deployment

    # CLI
    human companion deployment create \
      --name my-site \
      --surface-label my-site \
      --allowed-origins "https://yoursite.com"

    # Get the ready-to-paste snippet human companion deployment snippet my-site

    Proxy endpoint (Next.js App Router)

    // app/api/companion/ask/route.ts
    import { NextRequest, NextResponse } from 'next/server';

    const HUMAN_API_URL = process.env.HUMAN_API_URL ?? 'https://api.haio.run'; const INTERNAL_API_TOKEN = process.env.INTERNAL_API_TOKEN!;

    export async function POST(req: NextRequest) { const body = await req.json() as { text: string; deployment_id?: string; surface_context?: Record; };

    // Fetch deployment record (server-side; never expose delegation_token to browser) const depRes = await fetch( ${HUMAN_API_URL}/v1/companion/deployments/${body.deployment_id}, { headers: { Authorization: Bearer ${INTERNAL_API_TOKEN} } } ); const deployment = await depRes.json() as { delegation_token: string; allowed_origins: string[]; };

    // Validate origin const origin = req.headers.get('origin') ?? ''; if (!deployment.allowed_origins.includes(origin) && deployment.allowed_origins.length > 0) { return NextResponse.json({ error: 'Origin not allowed' }, { status: 403 }); }

    // Forward to HumanOS with the server-side token const agentRes = await fetch(${HUMAN_API_URL}/v1/agents/call, { method: 'POST', headers: { Authorization: Bearer ${deployment.delegation_token}, 'Content-Type': 'application/json', }, body: JSON.stringify({ target: 'agent://org/human/companion@0.1', input: { text: body.text, surface_context: { ...(body.surface_context ?? {}), deployment_id: body.deployment_id, }, }, }), });

    const data = await agentRes.json(); return NextResponse.json(data); }

    Embed snippet (paste before )

    
    

    React / Next.js usage

    import { CompanionWidget } from '@human/companion-widget/react';

    export function Layout({ children, pathname }) { return ( <> {children} ({ deployment_id: process.env.NEXT_PUBLIC_COMPANION_DEPLOYMENT_ID, surface_context: { surface: 'my-site', page: pathname, page_title: document.title, }, })} ui={{ theme: 'dark', position: 'bottom-right' }} /> ); }

    See Also

  • Deploying your first Companion instance
  • Context-aware Companion with SurfaceContext
  • Companion deployment management runbook