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

# Framework Examples

> Install and launch the SDK from Vanilla JS, React / Next.js, and Vue.js.

Copy-pasteable setups for the most common frameworks. Each one installs the SDK and launches the flow; the `/api/session` endpoint is covered in [Backend Integration](/public-embedded-signup-sdk/backend-integration).

<Note>
  These examples use `debug: true`, which logs the flow's progress to the browser console while you develop. To **receive the connected account in your code** — to save it or update your UI — add the `onSuccess` / `onError` / `onCancel` callbacks.
</Note>

<Tabs>
  <Tab title="React / Next.Js">
    ```tsx theme={null}
    'use client';

    import { useEffect, useRef, useState } from 'react';
    import { GatewayEmbeddedSignup, GatewayTheme } from '@connexease/gateway-embedded-signup';
    import type { GatewayEmbeddedSignupInstance } from '@connexease/gateway-embedded-signup';

    export function ConnectButton() {
      const widgetRef = useRef<GatewayEmbeddedSignupInstance | null>(null);
      const [loading, setLoading] = useState(false);

      useEffect(() => {
        widgetRef.current = GatewayEmbeddedSignup.init({
          publishableKey: process.env.NEXT_PUBLIC_GATEWAY_PUBLISHABLE_KEY!,
          theme: GatewayTheme.Blue,
          logoUrl: 'https://yourapp.com/logo.png',
          debug: true,
        });
        return () => { widgetRef.current?.destroy(); widgetRef.current = null; };
      }, []);

      const handleClick = async () => {
        if (!widgetRef.current || loading) return;
        setLoading(true);
        try {
          await widgetRef.current.launch({
            fetchSessionToken: async () => {
              const res = await fetch('/api/session', { method: 'POST' });
              if (!res.ok) throw new Error('Failed to fetch session');
              return res.json();
            },
            isCoexistence: false,	
    		secretKey: process.env.NEXT_PUBLIC_GATEWAY_SECRET_KEY,
          });
        } finally {
          setLoading(false);
        }
      };

      return (
        <button onClick={handleClick} disabled={loading}>
          {loading ? 'Connecting…' : 'Connect WhatsApp Business'}
        </button>
      );
    }
    ```

    **Backend :**
  </Tab>

  <Tab title="Vue.js">
    ```powershell theme={null}
    <template>
      <button @click="handleClick" :disabled="loading">
        {{ loading ? 'Connecting…' : 'Connect WhatsApp Business' }}
      </button>
    </template>

    <script setup lang="ts">
    import { ref, onMounted, onUnmounted } from 'vue';
    import { GatewayEmbeddedSignup, GatewayTheme } from '@connexease/gateway-embedded-signup';
    import type { GatewayEmbeddedSignupInstance } from '@connexease/gateway-embedded-signup';

    const loading = ref(false);
    let widget: GatewayEmbeddedSignupInstance | null = null;

    onMounted(() => {
      widget = GatewayEmbeddedSignup.init({
        publishableKey: import.meta.env.VITE_GATEWAY_PUBLISHABLE_KEY,
        theme: GatewayTheme.Blue,
        logoUrl: 'https://yourapp.com/logo.png',
        debug: true,
      });
    });

    onUnmounted(() => { widget?.destroy(); widget = null; });

    async function handleClick() {
      if (!widget || loading.value) return;
      loading.value = true;
      try {
        await widget.launch({
          fetchSessionToken: async () => {
            const res = await fetch('/api/session', { method: 'POST' });
            if (!res.ok) throw new Error('Failed to fetch session');
            return res.json();
          },
          isCoexistence: false,
    	  secretKey: process.env.NEXT_PUBLIC_GATEWAY_SECRET_KEY,
        });
      } finally {
        loading.value = false;
      }
    }
    </script>
    ```
  </Tab>

  <Tab title="Vanilla JS">
    ```javascript theme={null}
    <button id="connect-btn">Connect WhatsApp Business</button>

    <script src="https://cdn.connexease.com/embedded-signup/v0/sdk.js" defer></script>
    <script>
      const widget = window.GatewayEmbeddedSignup.init({
        publishableKey: 'pb_xxxxxxxxxxxxxxxxxxxxxx',
        theme: 'blue',
        logoUrl: 'https://yourapp.com/logo.png',
        debug: true,
      });

      document.getElementById('connect-btn').onclick = function () {
        widget.launch({
          fetchSessionToken: async function () {
            const res = await fetch('/api/session', { method: 'POST' });
            if (!res.ok) throw new Error('Failed to fetch session');
            return res.json();
          },
          isCoexistence: false,
    	  secretKey: 'sk_xxxxxxxxxxxxxxxxxxxxxx',
        });
      };
    </script>
    ```
  </Tab>
</Tabs>

```javascript theme={null}
const CONNEXEASE_SECRET_KEY = process.env.GATEWAY_SECRET_KEY;
const CONNEXEASE_API_BASE = process.env.GATEWAY_CORE_API_URL ?? 'https://public-api.gateway.connexease.com';
const SESSIONS_API = `${CONNEXEASE_API_BASE}/public/api/v1/wa/embedded-signup/sessions`;

export async function POST() {
  try {
    const res = await fetch(SESSIONS_API, {
      method: 'POST',
      headers: {
        'Authorization': `Bearer ${CONNEXEASE_SECRET_KEY}`,
        'Content-Type': 'application/json',
      },
    });

    const data = await res.json();
    if (!res.ok) return Response.json(data, { status: res.status });

    // Connexease wraps the payload as { data: {...}, isSuccess: true }
    return Response.json((data as any).data ?? data);
  } catch {
    return Response.json({ error: 'Failed to fetch session' }, { status: 500 });
  }
}
```

`.env`:

```bash theme={null}
NEXT_PUBLIC_GATEWAY_PUBLISHABLE_KEY=pb_xxxxxxxxxxxxxxxxxxxxxx
GATEWAY_SECRET_KEY=sk_xxxxxxxxxxxxxxxxxxxxxx
GATEWAY_CORE_API_URL=https://public-api.gateway.connexease.com  # optional; defaults to production
```

<Note>
  Only `NEXT_PUBLIC_`-prefixed vars reach the browser. `GATEWAY_SECRET_KEY` has **no** prefix, so it stays server-side in the Route Handler only.

  **Reminder:** `NEXT_PUBLIC_` values are baked in at build/dev-server start. If you add or change one, **restart the dev server** — it won't hot-reload.
</Note>
