rollfuse
← Voltar aos tutoriais

Rodando um Experimento A/B em uma Feature Flag

Um experimento A/B na rollfuse não é um sistema de targeting separado: ele funciona em cima de uma feature flag já existente. A flag continua controlando qual variação cada subject vê; o experimento adiciona uma hipótese, um ciclo de vida de início/fim e a camada estatística que lê exposições e observações para dizer qual variação venceu. Este tutorial cria um experimento em uma flag checkout-button-color, inicia esse experimento, avalia a flag pelo sdk-js e registra uma compra como métrica de conversão.

Criando o experimento na flag

Um experimento é criado sob a flag que ele testa, com POST /v1/feature-flags/{feature_flag_id}/experiments. Você precisa do ID da flag e de uma hipótese curta descrevendo o que espera que mude.

const flagId = "flag_checkout_button_color";

const res = await fetch(
  `https://api.rollfuse.com/v1/feature-flags/${flagId}/experiments`,
  {
    method: "POST",
    headers: {
      Authorization: `Bearer ${token}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      name: "Cor do botão de checkout",
      hypothesis: "CTA verde aumenta a conversão",
    }),
  },
);

const experiment = await res.json();
// experiment.id, experiment.status === "draft"

O experimento nasce no estado draft. Nada é atribuído a variação alguma e nada é medido ainda: o sdk-js continua avaliando a flag usando as regras de targeting que já existiam, então criar um experimento tem efeito zero no tráfego de produção até você iniciá-lo.

Iniciando o experimento

await fetch(
  `https://api.rollfuse.com/v1/experiments/${experiment.id}/start`,
  {
    method: "POST",
    headers: { Authorization: `Bearer ${token}` },
  },
);

Iniciar o experimento diz à plataforma para começar a distribuir subjects entre as variações da flag conforme a alocação configurada no experimento, e a passar a aceitar eventos de exposição e observação para ele. Você confirma que funcionou com GET /v1/experiments/{experiment_id}, checando status === "running".

Avaliando a flag no cliente e obtendo a variação

Nada muda na forma de chamar o SDK. client.evaluate() lê a Configuration da flag, que agora já traz as regras de bucketing do experimento em execução, e devolve a variação atribuída àquele subject.

import { RollfuseClient } from "@rollfuse/sdk-js";

const client = new RollfuseClient({
  baseUrl: "https://api.rollfuse.com",
  credential: process.env.ROLLFUSE_CREDENTIAL!, // set before running
});

await client.start();

const result = client.evaluate(userId, "checkout-button-color", {
  attributes: { plan: "growth" },
});

// result.value é "control" (cor padrão) ou "green" (tratamento)
renderCheckoutButton(result.value);

Como o bucketing é determinístico sobre (subjectKey, flagKey), o mesmo usuário continua vendo a mesma variação em sessões diferentes enquanto o experimento durar. O SDK reporta a exposição sozinho na primeira avaliação que bate com uma regra para aquele subject, usando o mesmo pipeline assíncrono de exposição já usado para flags comuns; você não precisa chamar o endpoint de exposure-events na mão a não ser que esteja registrando uma exposição que aconteceu fora do caminho de avaliação do SDK (por exemplo, uma página renderizada no servidor que já decidiu a variação antes de chegar ao cliente).

// só é necessário se você avaliou fora do SDK e precisa registrar a exposição manualmente
await fetch(
  `https://api.rollfuse.com/v1/experiments/${experiment.id}/exposure-events`,
  {
    method: "POST",
    headers: {
      Authorization: `Bearer ${token}`,
      "Content-Type": "application/json",
    },
    body: JSON.stringify({
      subject_key: userId,
      variation: result.value,
    }),
  },
);

Registrando uma conversão quando a ação alvo acontece

A métrica que um experimento mede não é inferida: você a reporta explicitamente, no momento em que o subject completa a ação que você definiu como objetivo. Para um teste de cor de botão de checkout, essa ação é finalizar uma compra.

async function onPurchaseComplete(userId, orderTotal) {
  await fetch(
    `https://api.rollfuse.com/v1/experiments/${experiment.id}/observations`,
    {
      method: "POST",
      headers: {
        Authorization: `Bearer ${token}`,
        "Content-Type": "application/json",
      },
      body: JSON.stringify({
        subject_key: userId,
        metric: "purchase_completed",
        value: orderTotal,
      }),
    },
  );
}

Essa chamada deve morar no mesmo trecho de código que já confirma o pedido, não em um job em background que pode rodar para um subject que nunca foi exposto ao experimento. Uma observação só é útil se puder ser cruzada com uma exposição do mesmo subject_key; uma compra de um usuário que nunca teve a flag avaliada não conta para nenhuma das variações.

Com o experimento rodando, exposições chegando do sdk-js e observações sendo registradas a cada compra concluída, você já tem tudo o que a plataforma precisa para calcular um resultado. O próximo passo, ler sample-ratio-mismatch e outcome-analysis para decidir entre concluir ou abortar, está em Lendo Resultados de Experimentos e Decidindo Quando Concluir.