# Custom Data

Alhena's Chat SDK lets you pass user metadata to personalize AI conversations and integrate with your backend systems. This page explains how to configure public metadata for AI prompts and private tokens for secure API calls.

## Overview

User metadata serves two purposes:

1. **Personalization** - Public metadata is available to the AI for context-aware responses
2. **Backend Integration** - Private metadata (API tokens, user IDs) enables custom tools to call your APIs

***

## Quick Reference

| Configuration                          | Where          | When to Use             |
| -------------------------------------- | -------------- | ----------------------- |
| `document.gleenConfig.userMetadata`    | Initial config | Set data at widget load |
| `window.gleenWidget.setUserMetadata()` | Runtime        | Update data dynamically |

| Key Prefix     | Visibility               | Example                     |
| -------------- | ------------------------ | --------------------------- |
| No prefix      | Public (AI can see)      | `email`, `name`, `plan`     |
| `_` underscore | Private (hidden from AI) | `_bearer_token`, `_user_id` |

***

## Public vs. Private Metadata

### Public Metadata

Keys **without** an underscore prefix are public. The AI can use this data to personalize responses.

```javascript
document.gleenConfig = {
    company: 'your-company-key',
    apiBaseUrl: 'https://app.alhena.ai',
    userMetadata: {
        email: 'john@example.com',    // AI sees this
        name: 'John Doe',              // AI sees this
        plan: 'premium',               // AI sees this
        locale: 'en-US'                // AI sees this
    }
};
```

**How the AI uses public metadata:**

* Greet users by name: "Hi John, how can I help?"
* Reference account type: "As a premium member, you have access to..."
* Personalize recommendations based on preferences

### Private Metadata

Keys starting with `_` (underscore) are private. These are **never** exposed to the AI but are available to custom API tools configured in your dashboard.

```javascript
document.gleenConfig = {
    company: 'your-company-key',
    apiBaseUrl: 'https://app.alhena.ai',
    userMetadata: {
        _bearer_token: 'eyJhbGciOiJIUzI1NiIs...',  // Hidden from AI
        _user_id: '12345',                          // Hidden from AI
        _session_id: 'abc-123-xyz'                  // Hidden from AI
    }
};
```

**Use private metadata for:**

* API authentication tokens
* Internal user/session identifiers
* Sensitive data that shouldn't appear in AI context

***

## Setting Metadata

### At Initialization

Pass metadata when the widget loads:

```html
<script>
document.gleenConfig = {
    company: 'your-company-key',
    apiBaseUrl: 'https://app.alhena.ai',
    userMetadata: {
        // Public - available to AI
        email: 'user@example.com',
        name: 'Jane Smith',
        membership: 'gold',

        // Private - only for API tools
        _api_token: 'secret-token-value',
        _customer_id: 'cust_12345'
    }
};
</script>
<script src="https://app.alhena.ai/sdk/gleenWidget.js"></script>
```

### Dynamic Updates

Update metadata at runtime using `setUserMetadata(key, value)`. Each call sets a single field:

```javascript
// After user logs in
window.gleenWidget.setUserMetadata('email', currentUser.email);
window.gleenWidget.setUserMetadata('name', currentUser.name);
window.gleenWidget.setUserMetadata('_session_token', currentUser.sessionToken);
```

```javascript
// Update a specific field
window.gleenWidget.setUserMetadata('plan', 'enterprise');
```

***

## Common Use Cases

### User Identification

Pass user details after authentication for personalized support:

```javascript
// When user logs in
function onUserLogin(user) {
    window.gleenWidget.setUserMetadata('email', user.email);
    window.gleenWidget.setUserMetadata('name', user.displayName);
    window.gleenWidget.setUserMetadata('account_type', user.accountType);
    window.gleenWidget.setUserMetadata('signup_date', user.createdAt);
    window.gleenWidget.setUserMetadata('_user_id', user.id);
}
```

### Passing Cart Data

Pass the customer's current cart to enable the AI to answer questions about items in their cart, provide checkout assistance, or make recommendations.

{% hint style="info" %}
**Shopify stores**: Cart data is passed automatically when you install the Alhena widget. No additional configuration needed.
{% endhint %}

For other platforms, fetch cart data and pass it using `setUserMetadata`:

**WooCommerce:**

```javascript
window.gleenWidget.on('widget:loaded', async function() {
    try {
        // WooCommerce Store API (requires WC 5.0+)
        const response = await fetch('/wp-json/wc/store/v1/cart');
        const cart = await response.json();

        const cartData = {
            items: cart.items.map(item => ({
                title: item.name,
                quantity: item.quantity,
                price: item.prices.price / 100,
                options: item.variation || []
            })),
            currency: cart.totals.currency_code,
            subtotal: parseInt(cart.totals.total_items) / 100,
            checkout_url: window.location.origin + '/checkout/'
        };

        window.gleenWidget.setUserMetadata('current_cart', cartData);
    } catch (error) {
        console.error('Failed to fetch cart:', error);
    }
});
```

**Magento:**

```javascript
window.gleenWidget.on('widget:loaded', async function() {
    try {
        const response = await fetch('/rest/V1/carts/mine', {
            headers: {
                'Authorization': 'Bearer ' + customerToken
            }
        });
        const cart = await response.json();

        const cartData = {
            items: cart.items.map(item => ({
                title: item.name,
                quantity: item.qty,
                price: item.price,
                options: item.product_option?.extension_attributes || []
            })),
            currency: cart.currency.quote_currency_code,
            subtotal: cart.subtotal,
            checkout_url: window.location.origin + '/checkout/'
        };

        window.gleenWidget.setUserMetadata('current_cart', cartData);
    } catch (error) {
        console.error('Failed to fetch cart:', error);
    }
});
```

**Custom Platform / Generic:**

```javascript
window.gleenWidget.on('widget:loaded', function() {
    // Replace with your cart data source
    const cart = getYourCartData();

    const cartData = {
        items: cart.items.map(item => ({
            title: item.productName,
            quantity: item.quantity,
            price: item.unitPrice,
            options: item.selectedOptions || []
        })),
        currency: cart.currency || 'USD',
        subtotal: cart.subtotalAmount,
        checkout_url: window.location.origin + '/checkout'
    };

    window.gleenWidget.setUserMetadata('current_cart', cartData);
});

// Update cart when it changes
function onCartUpdated(cart) {
    const cartData = {
        items: cart.items.map(item => ({
            title: item.productName,
            quantity: item.quantity,
            price: item.unitPrice,
            options: item.selectedOptions || []
        })),
        currency: cart.currency || 'USD',
        subtotal: cart.subtotalAmount,
        checkout_url: window.location.origin + '/checkout'
    };

    window.gleenWidget.setUserMetadata('current_cart', cartData);
}
```

**Cart data structure:**

| Field              | Type   | Description                    |
| ------------------ | ------ | ------------------------------ |
| `items`            | Array  | List of cart items             |
| `items[].title`    | String | Product name                   |
| `items[].quantity` | Number | Quantity in cart               |
| `items[].price`    | Number | Unit price                     |
| `items[].options`  | Array  | Selected variants/options      |
| `currency`         | String | Currency code (USD, EUR, etc.) |
| `subtotal`         | Number | Cart subtotal amount           |
| `checkout_url`     | String | URL to checkout page           |

### Backend API Integration

Pass tokens for custom tools that call your APIs:

```javascript
// Get token from your authentication system
const userToken = await getAuthToken();

document.gleenConfig = {
    company: 'your-company-key',
    apiBaseUrl: 'https://app.alhena.ai',
    userMetadata: {
        email: currentUser.email,
        _bearer_token: userToken,
        _api_key: process.env.API_KEY
    }
};
```

{% hint style="info" %}
**Setting up API Tools**: Create custom API tools in the Alhena dashboard under **Settings > API Tools**. These tools can use private metadata values to authenticate requests to your backend.
{% endhint %}

***

## Complete Example

```html
<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Personalized Chat Widget</title>
</head>
<body>

<div id="user-info">
    <span id="greeting">Welcome, Guest</span>
    <button id="login-btn">Log In</button>
    <button id="logout-btn" style="display:none">Log Out</button>
</div>

<!-- Alhena SDK with initial metadata -->
<script>
// Initial configuration for anonymous users
document.gleenConfig = {
    company: 'your-company-key',
    apiBaseUrl: 'https://app.alhena.ai',
    userMetadata: {
        visitor_type: 'anonymous',
        page_url: window.location.href
    }
};
</script>
<script src="https://app.alhena.ai/sdk/gleenWidget.js"></script>

<script>
// Simulated user data
const mockUser = {
    id: 'user_12345',
    email: 'jane@example.com',
    name: 'Jane Smith',
    plan: 'premium',
    token: 'eyJhbGciOiJIUzI1NiIs...'
};

// Login handler
document.getElementById('login-btn').addEventListener('click', function() {
    // Update UI
    document.getElementById('greeting').textContent = 'Welcome, ' + mockUser.name;
    document.getElementById('login-btn').style.display = 'none';
    document.getElementById('logout-btn').style.display = 'inline';

    // Update chat widget with user data
    // Public data for AI personalization
    window.gleenWidget.setUserMetadata('email', mockUser.email);
    window.gleenWidget.setUserMetadata('name', mockUser.name);
    window.gleenWidget.setUserMetadata('plan', mockUser.plan);
    window.gleenWidget.setUserMetadata('visitor_type', 'authenticated');

    // Private data for API integrations
    window.gleenWidget.setUserMetadata('_user_id', mockUser.id);
    window.gleenWidget.setUserMetadata('_bearer_token', mockUser.token);
});

// Logout handler
document.getElementById('logout-btn').addEventListener('click', function() {
    // Update UI
    document.getElementById('greeting').textContent = 'Welcome, Guest';
    document.getElementById('login-btn').style.display = 'inline';
    document.getElementById('logout-btn').style.display = 'none';

    // Reset to anonymous state
    window.gleenWidget.setUserMetadata('visitor_type', 'anonymous');
    window.gleenWidget.setUserMetadata('email', null);
    window.gleenWidget.setUserMetadata('name', null);
    window.gleenWidget.setUserMetadata('plan', null);
    window.gleenWidget.setUserMetadata('_user_id', null);
    window.gleenWidget.setUserMetadata('_bearer_token', null);
});
</script>

</body>
</html>
```

***

## Security Best Practices

1. **Never expose sensitive credentials** - Always use the `_` prefix for tokens and secrets
2. **Rotate tokens** - Use short-lived tokens when possible
3. **Validate on backend** - Your API tools should still validate tokens server-side
4. **Limit metadata scope** - Only pass data that's needed for personalization or integration

***

## Related Resources

* [JavaScript API](https://alhena.gitbook.io/docs/developer-reference/website-sdk/javascript-api) - Complete method reference
* [Events](https://alhena.gitbook.io/docs/developer-reference/website-sdk/events) - Widget event reference
* [Examples](https://alhena.gitbook.io/docs/developer-reference/website-sdk/examples) - Code examples for common use cases


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://alhena.gitbook.io/docs/developer-reference/website-sdk/custom-data.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
