Skip to main content
Uma pesquisa é uma pergunta. O que a torna usável num produto em vez de irritante está inteiro na aritmética em volta: quem é perguntado, quando, com que frequência alguém pode ser perguntado, e o que uma resposta repetida faz.

Dois tipos

nps é a pergunta com escala fixa de 0 a 10 e aritmética fixa — é o tipo do qual a tela de resultados consegue calcular um número. custom é qualquer outra coisa, onde o verbatim costuma ser a resposta. O tipo não pode mudar depois de criado: as notas já dadas foram dadas na escala antiga.

Quando ela dispara

Uma pesquisa carrega até cinco gatilhos. Os dois primeiros são casados por um consumidor conforme os fatos chegam, em segundos. O terceiro é varrido, porque nada é publicado quando o trigésimo dia de alguém chega — não há fato, já que nada aconteceu. days_after_created só conta aniversários que caem depois de a pesquisa ter sido escrita. Ligar “pergunte no dia 30” não questiona sua base inteira de uma vez, que é o que uma implementação ingênua faz na primeira execução e não dá para desfazer. Uma pessoa é perguntada uma vez por ocasião, para sempre: a primeira vez que aquele fato é verdade sobre ela, a primeira vez que ela entra naquela audiência, o seu N-ésimo dia. Reentrar num segmento não é nova ocasião — sair e voltar é ruído de churn e não um momento. Uma pesquisa recorrente (“pergunte o NPS de todo mundo a cada trimestre”) ainda não existe, e um intervalo longo deliberadamente não a imita. Ela é um quarto tipo de gatilho com um período na identidade, e até existir a resposta honesta é que isso não pode ser perguntado.

O intervalo pertence à pessoa

cooldown_days (padrão 7) é por quanto tempo uma entrega fecha a porta para qualquer pesquisa daquele contato — não para aquela pesquisa. É essa a promessa inteira. “Ninguém é pesquisado duas vezes por semana” não é verdade numa janela por pesquisa: três pesquisas perguntando no máximo uma vez por dia cada estariam todas dentro do próprio limite e a pessoa seria perguntada três vezes. 0 é permitido e significa sem intervalo, o que é uma resposta real para um ambiente rodando exatamente uma pesquisa. Reivindicar uma entrega é uma só instrução, e a contagem de linhas é a decisão. A audiência, a identificação, a atividade e a janela são todas checadas dentro de um INSERT, porque um SELECT seguido de INSERT são duas fotografias de uma tabela — e duas entregas correndo sobre o mesmo contato encontrariam as duas nada pendente e as duas escreveriam.

A leitura do widget

Onde o cartão é desenhado

position aceita center (padrão), bottom-right, bottom-center, bottom-left ou inline. Só o center toma a página. Ele escurece o fundo, leva o foco para dentro do cartão e fecha no Esc ou num clique fora. Os dois cantos não escurecem nada, de propósito: uma pergunta no canto é uma que a pessoa pode terminar a frase antes de responder, e escurecer o produto para perguntar sobre o produto é o que faz um NPS de cinco segundos parecer um pedágio. Eles são anunciados a um leitor de tela como diálogo, mas não como modal — porque o resto do seu produto continua mesmo disponível. inline é o componente no seu próprio layout, que é o que ele fazia antes de haver escolha — certo para uma tela de configurações ou qualquer lugar onde você já abriu espaço para ele. As três posições flutuantes saem da árvore do componente por portal, então nenhum overflow ou contexto de empilhamento de um ancestral consegue recortá-las. Os cantos ficam onde um launcher de suporte costuma ficar, então se você também desenha o <HelpWidget /> à direita, ponha a pesquisa à esquerda. Um diálogo no centro por vez, e há uma ordem. Três coisas se abrem sozinhas no meio da página — um termo pendente, uma novidade não lida e esta pesquisa — e cada uma descobre que quer a tela quando a resposta dela volta. Sem regra, as três aparecem juntas, cada uma dizendo aria-modal="true" a um leitor de tela. O centro passa a caber uma: a ordem padrão é agreementswhatsNewsurvey (a condição que o tenant declarou, depois o que ele publicou, depois o favor que ele está pedindo), e quem espera não perde nada — a pesquisa só é gasta quando é respondida, então ela aparece assim que a de cima sair, ou na próxima visita. Quem já está na tela não é trocado por alguém de ordem maior que chegou depois: puxar o cartão da mão de quem está lendo é pior do que a ordem sair imperfeita numa visita. E um diálogo que a pessoa PEDIU — o seletor de metas do guia, por exemplo — fura a fila, porque ele responde a um clique. A fila é só do center. Um cartão no canto ou no fluxo não disputa palco com ninguém. Para trocar a ordem:
Esc e o clique fora são “agora não”, nunca uma resposta. Eles escondem o cartão nesta página e não gastam nada, então a pessoa é perguntada de novo na próxima visita — um reflexo não é uma recusa. Num app Next, importe do @userkit/nextjs — é o mesmo componente, e em modo proxy a leitura e a resposta são encaminhadas pelos handlers como o resto da superfície do contato, com a sessão num cookie httpOnly da sua própria origem.
pending nomeia uma ocasião, não uma pesquisa. Nada aqui pede uma — a API decide quem é perguntado, a partir de um gatilho, uma audiência e o intervalo — que é por que não existe requestSurvey e por que uma lista vazia é a resposta comum. Uma entrega não respondida fica pendente por 14 dias. Uma pergunta que ninguém respondeu em duas semanas não é uma pergunta que a pessoa ainda deve, e um widget que abre uma pesquisa de março é um widget que as pessoas aprendem a dispensar sem ler. No máximo cinco são devolvidas. Responder gasta a entrega: uma segunda chamada responde not_found, que é literalmente “você não foi perguntado isso” — a mesma coisa que uma ocasião retirada ou vencida diz. Um widget clicado duas vezes escreve uma resposta, porque a escrita só acontece se a entrega puder ser marcada como respondida por um UPDATE levando responded_at IS NULL. Uma pesquisa nps exige a nota. Uma escala respondida só com uma frase é um verbatim sem nada para dividir, e deixar passar colocaria uma resposta no numerador de uma taxa da qual ela não faz parte. Qualquer outro tipo aceita nota, comentário, ou os dois. Desligar uma pesquisa também faz suas entregas pendentes deixarem de ser pendentes.

Resultados

score é promotores menos detratores sobre scored, em porcentagem, e é null quando ninguém pontuou — nunca 0. Zero é um NPS real e um número sobre o qual alguém agiria; “ainda sem respostas” e “um resultado genuinamente neutro” não podem ser desenhados iguais. delivered é o denominador da sua taxa de resposta; scored é o denominador da nota. Eles diferem sempre que alguém responde uma pesquisa custom só com palavras. A tendência é semanal sobre os últimos 180 dias, em semanas UTC — a mesma meia-noite que todo o resto usa.

A nota alcança o resto do produto por JOIN

A leitura de um contato leva latest_survey_score, e isso é um JOIN e não uma coluna no contato. Deliberadamente: uma cópia é um segundo lugar que pode discordar, alargaria a tabela mais quente do plano de clientes, e guardaria exatamente a única resposta que o JOIN sempre consegue produzir. É null quando ninguém respondeu. É isso que permite uma nota baixa ficar ao lado de sinais de churn na mesma tela sem ninguém construir um pipeline. survey.response_recorded é entregável como webhook, que é o gancho para “encaminhe um detrator a um humano hoje”.

O que ainda não está aqui

Entrega por e-mail. Tudo acima é in-app: uma pesquisa é entregue a um widget que a pessoa abriu, e não existe versão dela por e-mail. O que existe ao lado são as campanhas, que podem enviar um template com a categoria surveys — um público, uma sequência, um limite e um link de descadastro. Isso é uma mensagem sobre perguntar; não cria uma entrega de pesquisa, e uma resposta a ela não é uma resposta nos resultados acima.

Permissões

engagement:manage — owner e admin por padrão, compartilhada com checklists e o changelog.