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.