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

# useExperiment()

> Hook principal para implementar testes A/B no seu componente React

## Visão Geral

O hook `useExperiment` é a forma principal de implementar experimentos A/B no Testly.

Ele gerencia automaticamente:

* ✅ Atribuição determinística de variantes
* ✅ Registro automático de impressões
* ✅ Cache local para consistência
* ✅ Estados de loading e erro

***

## Uso Básico

```tsx theme={null}
import { useExperiment } from '@testlyjs/react';

function MyComponent() {
  const { variant, loading, error, convert } = useExperiment('experiment-id');

  if (loading) return <div>Carregando...</div>;
  if (error) return <div>Erro ao carregar experimento</div>;

  return (
    <div>
      {variant === 'variant-b' ? (
        <button onClick={() => convert('clicked')}>Variante B</button>
      ) : (
        <button onClick={() => convert('clicked')}>Variante A (Controle)</button>
      )}
    </div>
  );
}
```

***

## Assinatura

```typescript theme={null}
const {
  variant,
  loading,
  error,
  convert
} = useExperiment(experimentId, options?);
```

### Parâmetros

| Parâmetro      | Tipo     | Obrigatório | Descrição                                   |
| -------------- | -------- | ----------- | ------------------------------------------- |
| `experimentId` | `string` | ✅ Sim       | ID único do experimento criado no dashboard |
| `options`      | `object` | ❌ Não       | Opções de configuração do experimento       |

### Opções

```typescript theme={null}
interface UseExperimentOptions {
  fallback?: string;                         // Variante padrão antes de carregar (opcional)
  onAssignment?: (variant: string) => void;  // Callback quando variante é atribuída (opcional)
}
```

### Retorno

```typescript theme={null}
interface UseExperimentResult {
  variant: string | null;           // Chave da variante atribuída
  variantId: string | null;         // UUID interno da variante
  experimentId: string | null;      // UUID interno do experimento
  loading: boolean;                 // true enquanto carrega
  error: Error | null;              // Erro se houver falha
  convert: (eventName: string) => Promise<void>; // Função para registrar conversão
}
```

***

## Exemplos Práticos

### Exemplo 1: Teste de CTA

```tsx theme={null}
import { useExperiment } from '@testlyjs/react';

export function HeroSection() {
  const { variant, loading, error, convert } = useExperiment('homepage-hero-cta');

  if (loading) {
    return (
      <section className="hero">
        <h1>Transforme seu produto com dados</h1>
        <div className="skeleton-button" />
      </section>
    );
  }

  if (error) {
    console.error('Erro no experimento:', error);
    // Fallback para versão original
    return (
      <section className="hero">
        <h1>Transforme seu produto com dados</h1>
        <button onClick={() => window.location.href = '/signup'}>
          Comece Grátis
        </button>
      </section>
    );
  }

  const handleClick = () => {
    convert('hero_cta_clicked');
    window.location.href = '/signup';
  };

  return (
    <section className="hero">
      <h1>Transforme seu produto com dados</h1>
      
      {variant === 'variant-b' ? (
        <button onClick={handleClick} className="cta-primary">
          Experimente Agora 🚀
        </button>
      ) : (
        <button onClick={handleClick} className="cta-primary">
          Comece Grátis
        </button>
      )}
    </section>
  );
}
```

### Exemplo 2: Teste de Layout

```tsx theme={null}
import { useExperiment } from '@testlyjs/react';

export function PricingSection() {
  const { variant, convert } = useExperiment('pricing-layout');

  const handleSelectPlan = (planName: string) => {
    convert('plan_selected');
    // Redirecionar para checkout
  };

  // Layout de 3 colunas (Variante B)
  if (variant === 'variant-b') {
    return (
      <section className="pricing-3-col">
        <PricingCard plan="Free" onSelect={handleSelectPlan} />
        <PricingCard plan="Pro" onSelect={handleSelectPlan} featured />
        <PricingCard plan="Enterprise" onSelect={handleSelectPlan} />
      </section>
    );
  }

  // Layout de 2 colunas (Controle)
  return (
    <section className="pricing-2-col">
      <PricingCard plan="Free" onSelect={handleSelectPlan} />
      <PricingCard plan="Pro" onSelect={handleSelectPlan} featured />
    </section>
  );
}
```

### Exemplo 3: Teste de Múltiplas Variantes

```tsx theme={null}
import { useExperiment } from '@testlyjs/react';

export function ProductHero() {
  const { variant, convert } = useExperiment('hero-headline');

  const headlines = {
    'control': 'A/B Testing para Founders Devs',
    'variant-b': 'Valide suas Ideias com Dados Reais',
    'variant-c': 'Experimentos A/B sem Complicação',
    'variant-d': 'Teste. Aprenda. Melhore.'
  };

  const handleCTA = () => {
    convert('cta_clicked');
    window.location.href = '/signup';
  };

  return (
    <section className="hero">
      <h1>{headlines[variant] || headlines.control}</h1>
      <p>Implemente testes A/B em 5 minutos com nosso SDK React.</p>
      <button onClick={handleCTA}>
        Começar Grátis
      </button>
    </section>
  );
}
```

### Exemplo 4: Teste Condicional

```tsx theme={null}
import { useExperiment } from '@testlyjs/react';

export function FeatureSection() {
  const { variant, convert } = useExperiment('social-proof-test');

  return (
    <section className="features">
      <h2>Por que escolher o Testly?</h2>
      
      <FeatureList />

      {/* Mostrar social proof apenas na Variante B */}
      {variant === 'variant-b' && (
        <div className="social-proof">
          <div className="testimonials">
            <Testimonial author="João Silva" role="CTO @ StartupXYZ" />
            <Testimonial author="Maria Santos" role="Founder @ SaaSCo" />
          </div>
          <button onClick={() => convert('social_proof_cta_clicked')}>
            Ver Mais Depoimentos
          </button>
        </div>
      )}
    </section>
  );
}
```

***

## Comportamento do Hook

### Primeira Renderização

1. Hook é executado
2. Verifica cache local
3. Se não encontrar, chama a API
4. API atribui variante de forma determinística
5. **Impressão é registrada automaticamente**
6. Variante é salva no cache
7. Componente re-renderiza com a variante

### Renderizações Subsequentes

1. Hook busca variante do cache
2. Retorna imediatamente (sem chamada à API)
3. **Não registra nova impressão**
4. Mantém consistência da experiência

<Note>
  O registro de impressão é **automático** e acontece apenas na primeira vez que o usuário vê o experimento. Você não precisa fazer nada!
</Note>

***

## Conversões

A função `convert()` permite registrar quando o usuário completa a ação desejada.

### Sintaxe

```typescript theme={null}
convert(eventName: string): Promise<void>
```

### Parâmetros

| Parâmetro   | Tipo     | Descrição                                                    |
| ----------- | -------- | ------------------------------------------------------------ |
| `eventName` | `string` | Nome do evento de conversão (ex: `'clicked'`, `'signed_up'`) |

### Exemplos de Conversão

```tsx theme={null}
// Conversão simples
<button onClick={() => convert('button_clicked')}>
  Clique Aqui
</button>

// Conversão com ação posterior
<button onClick={async () => {
  await convert('form_submitted');
  router.push('/thank-you');
}}>
  Enviar Formulário
</button>

// Conversão com tratamento de erro
<button onClick={async () => {
  try {
    await convert('purchase_completed');
    showSuccessMessage();
  } catch (error) {
    console.error('Falha ao registrar conversão:', error);
    // A ação continua mesmo se o tracking falhar
  }
}}>
  Finalizar Compra
</button>
```

<Tip>
  **Boas práticas para nomes de eventos**:

  * Use snake\_case: `button_clicked`, `form_submitted`
  * Seja descritivo: `hero_cta_clicked` > `click`
  * Use verbos no passado: `clicked`, `submitted`, `completed`
</Tip>

***

## Estados de Loading e Erro

### Loading State

Sempre implemente um estado de loading para evitar Layout Shift:

```tsx theme={null}
const { variant, loading } = useExperiment('test');

if (loading) {
  return <Skeleton />; // Placeholder com mesmo tamanho
}
```

### Error State

Sempre tenha um fallback para erros:

```tsx theme={null}
const { variant, error } = useExperiment('test');

if (error) {
  // Log do erro (opcional)
  console.error('Erro no experimento:', error);
  
  // Retornar versão original/segura
  return <OriginalVersion />;
}
```

<Warning>
  **Importante**: Nunca deixe seu app quebrar por causa de um experimento. Sempre implemente fallbacks que mantêm a funcionalidade.
</Warning>

***

## Múltiplos Experimentos

Você pode rodar vários experimentos no mesmo componente:

```tsx theme={null}
export function ProductPage() {
  const heroTest = useExperiment('hero-test');
  const pricingTest = useExperiment('pricing-test');
  const ctaTest = useExperiment('cta-test');

  return (
    <div>
      <Hero 
        variant={heroTest.variant} 
        onConvert={heroTest.convert} 
      />
      
      <Pricing 
        variant={pricingTest.variant}
        onConvert={pricingTest.convert}
      />
      
      <CTA 
        variant={ctaTest.variant}
        onConvert={ctaTest.convert}
      />
    </div>
  );
}
```

<Note>
  Cada experimento é independente. Um usuário pode ver Variante A no hero e Variante B no pricing simultaneamente.
</Note>

***

## Boas Práticas

### 1. Sempre implemente Loading e Error

```tsx theme={null}
// ✅ Bom
const { variant, loading, error } = useExperiment('test');
if (loading) return <Skeleton />;
if (error) return <Fallback />;

// ❌ Ruim (pode quebrar o app)
const { variant } = useExperiment('test');
return <div>{variant}</div>;
```

### 2. Nomear variantes de forma clara

```tsx theme={null}
// ✅ Bom (descritivo)
if (variant === 'variant-b') { ... }
if (variant === 'control') { ... }

// ❌ Ruim (confuso)
if (variant === 'v2') { ... }
if (variant === 'new') { ... }
```

### 3. Isolar lógica de experimento

```tsx theme={null}
// ✅ Bom (fácil de remover depois)
const { variant, convert } = useExperiment('test');
const buttonText = variant === 'variant-b' 
  ? 'Experimente Agora' 
  : 'Comece Grátis';

return <button onClick={() => convert('clicked')}>{buttonText}</button>;

// ❌ Ruim (lógica espalhada)
return variant === 'variant-b' ? (
  <div>
    <h1>Título B</h1>
    <button>Experimente Agora</button>
    <p>Copy B</p>
  </div>
) : (
  <div>
    <h1>Título A</h1>
    <button>Comece Grátis</button>
    <p>Copy A</p>
  </div>
);
```

### 4. Testar apenas UMA variável

```tsx theme={null}
// ✅ Bom (testa apenas o texto)
const buttonText = variant === 'variant-b' ? 'Texto B' : 'Texto A';

// ❌ Ruim (muda texto + cor + tamanho)
if (variant === 'variant-b') {
  return <button className="big blue">Texto B</button>;
}
```

***

## TypeScript

O hook é totalmente tipado:

```typescript theme={null}
import { useExperiment } from '@testlyjs/react';

// Tipos básicos são inferidos automaticamente
const { variant, loading, error, convert } = useExperiment('test');

// Você pode especificar o tipo da variante
type MyVariants = 'control' | 'variant-b' | 'variant-c';
const { variant } = useExperiment<MyVariants>('test');

// Agora variant tem autocomplete com os valores possíveis
if (variant === 'variant-b') { // ✅ Autocomplete funciona
  // ...
}
```

***

## Troubleshooting

<AccordionGroup>
  <Accordion title="variant retorna null — causa mais comum" icon="circle-xmark">
    **A causa número 1**: a API Key no `TestlyProvider` não corresponde à organização onde o experimento foi criado.

    O SDK envia a API Key para o servidor, que busca o experimento dentro daquela organização. Se você usar a key de uma conta diferente, o servidor não encontra o experimento e retorna `null`.

    **Checklist**:

    1. Abra [app.testly.com.br/settings](https://app.testly.com.br/settings) → copie a API Key (`tk_live_...`)
    2. Confirme que **essa mesma key** está no `TestlyProvider` do seu app
    3. Confirme que o slug em `useExperiment('...')` é exatamente igual ao slug do dashboard (case-sensitive)
    4. Confirme que o experimento está em estado **running** no dashboard (não draft, paused ou completed)

    Ative o debug para inspecionar a resposta do servidor:

    ```tsx theme={null}
    <TestlyProvider apiKey="..." config={{ debug: true }}>
    ```
  </Accordion>

  <Accordion title="Loading nunca termina" icon="spinner">
    **Possíveis causas**:

    1. Problema de rede ou firewall bloqueando o endpoint
    2. API Key inválida (formato incorreto)
    3. Experimento inativo — retorna `null` imediatamente, não fica em loading

    **Solução**:

    * Verifique o console do navegador por erros de rede
    * Confirme que a API Key tem o formato `tk_live_...`
    * Ative `debug: true` e verifique os logs
  </Accordion>

  <Accordion title="Conversões não são registradas" icon="chart-line">
    **Checklist**:

    * ✅ Você está chamando `convert('event_name')`?
    * ✅ O nome do evento é uma string válida?
    * ✅ Você registrou impressão (automático) antes?
    * ✅ Debug mode está ativo para ver logs?

    **Teste**:

    ```tsx theme={null}
    convert('test_event').then(() => {
      console.log('✅ Conversão registrada');
    }).catch(err => {
      console.error('❌ Erro:', err);
    });
    ```
  </Accordion>

  <Accordion title="Variante muda a cada refresh" icon="arrows-rotate">
    **Isso não deveria acontecer!**

    O Testly usa cache local para garantir consistência.

    **Possíveis causas**:

    1. localStorage está sendo limpo
    2. Navegação privada/anônima
    3. Diferentes `userId` sendo gerados

    **Solução**:

    * Verifique se não há código limpando localStorage
    * Use um `userId` fixo para testar
  </Accordion>
</AccordionGroup>

***

## Próximos Passos

<CardGroup cols={2}>
  <Card title="Exemplos Práticos" icon="lightbulb" href="/examples/hero-section">
    Veja implementações reais de A/B tests
  </Card>

  <Card title="Configuração" icon="gear" href="/sdk/configuration">
    Opções avançadas do SDK
  </Card>

  <Card title="Debugging" icon="bug" href="/guides/debugging">
    Guia completo de troubleshooting
  </Card>
</CardGroup>
