Widget B2C — visitante convidado e empresa
Esta secção cobre as integrações em que o widget fica em sessão de convidado:
- site público, visitante desconhecido: só o script e o formulário de contacto
- site ou portal que já conhece a conta:
init()com perfil e dados da empresa, formulário omitido quando os dados chegam, contacto ligado à empresa
O histórico pessoal noutro browser ou dispositivo é outra integração. Vê Widget B2B. Contrato completo dos campos, mudança de conta numa SPA, CSP e provisioning: Integração técnica.
Associar uma empresa não autoriza o histórico de outra pessoa. Um utilizador autenticado no site continua a ser um convidado do widget até enviares external_user_id juntamente com um restore_id válido.
O que obténs
- Um botão flutuante, ou um chat incorporado num contentor da página
- Um formulário inicial para quem é desconhecido, com as etiquetas Telefone e Nome. Em
init()os campos sãophoneename - Uma sessão de convidado guardada pelo loader no mesmo browser, separada por chave de widget. Se o
localStorageestiver bloqueado, a continuidade pode ficar na página atual - Se envias
external_id, a Quoting24 procura uma empresa com o mesmoweb_code. Comcompany_nametambém, pode criar a empresa em falta e ligar o contacto - Tickets e respostas na Quoting24, como nos outros canais
A sessão de convidado relê a sua conversa mais recente mesmo depois de fechar o separador. Não segue a pessoa para outro browser.
1. Pré-requisitos na Quoting24
- Canal Widget ativo em Definições → Canais
- Logótipo, cor, posição, saudação, boas-vindas e fora de horário configurados
- Domínios permitidos atualizados, incluindo testes e
localhost - Código de incorporação copiado da configuração do canal: URL do script e chave pública
Usa o host e a chave do mesmo ambiente. Nos exemplos substitui HOST_WIDGET e CHAVE_PUBLICA_WIDGET.
Os domínios são nomes de host, sem https://, porta, caminho ou *.. example.com inclui os subdomínios. Lista vazia: nenhuma restrição. Em local serve a página por HTTP, não como file://.
O company_name de init() é a denominação social do cliente. Não é o título do widget e não se configura a partir deste payload.
2. Instalar o botão flutuante
Cola o script uma só vez, antes de </body>:
O botão aparece depois de carregar as definições gráficas. Um visitante novo vê o formulário de contacto. Quem volta no mesmo browser retoma a sessão de convidado, se o armazenamento estiver disponível.
O script expõe um único window.Quoting24Widget.
3. Incorporar o chat na página
Cria o contentor antes do script e dá-lhe uma altura explícita:
<section aria-labelledby="titulo-assistencia">
<h2 id="titulo-assistencia">Assistência</h2>
<div id="chat-assistencia" style="width: 100%; height: 600px;"></div>
</section>
<script
src="https://HOST_WIDGET/assets/widget/script.js?key=CHAVE_PUBLICA_WIDGET&mode=embedded&target=chat-assistencia"
async
></script>
targeté o ID do elemento, sem#- O iframe preenche o contentor
- Não há botão flutuante
open(),close()etoggle()não têm efeito- Neste modo o site decide a altura e a largura. No modo flutuante, no telemóvel, o chat pode ocupar o viewport
O modo incorporado, por si só, não ativa o restauro do histórico.
4. Enviar o perfil do cliente
Quando o site conhece a conta, envia o perfil depois de carregar o loader. Os campos são cadeias. Omite os desconhecidos: não envies null, IDs numéricos nem um e-mail vazio.
window.Quoting24Widget.init({
external_id: "52",
company_name: "Ricambi Stella S.r.l.",
name: "mario.rossi",
phone: "+393331234567",
email: "amministrazione@ricambi-stella.example",
});
| Dado no site ou no ERP | Campo | Significado |
|---|---|---|
Referência estável da empresa, o mesmo valor importado em web_code |
external_id |
Comparação exata com companies.web_code, na organização do widget |
| Denominação social | company_name |
Usada se for preciso criar a empresa |
| Nome da pessoa ou do utilizador | name |
Nome mostrado no contacto |
| E-mail da conta | email |
Guardado na empresa só quando a empresa é criada |
| Telefone, se o conheceres | phone |
Número do contacto. Prefere o formato internacional, por exemplo +393331234567 |
Este payload não envia external_user_id nem restore_id. Mantém name e company_name separados: não concatenes a denominação social ao nome de utilizador para obter a associação. O campo público é external_id. Não envies web_code, o UUID interno da Quoting24 nem companies.code.
O formulário mostra Nome e Telefone. Em init() esses campos chamam-se name e phone. O e-mail chama-se email. Nome, Telefone e Email não são chaves: o loader descarta-as, como descarta web_code no lugar de external_id.
Exemplos
Nome e telefone, os mesmos dados do formulário. O chat começa e não procura uma empresa.
Perfil com empresa. name é a pessoa, phone o número do contacto e email fica na empresa só se esta chamada a criar.
widget.init({
external_id: "52",
company_name: "Ricambi Stella S.r.l.",
name: "Mario Rossi",
phone: "+393331234567",
email: "mario.rossi@ricambi-stella.example",
});
Só e-mail. Um endereço válido em email chega para abrir a sessão.
Se um campo ultrapassar os limites ou o e-mail estiver mal formado, o pedido é rejeitado. Limites e comportamento de cada campo: Integração técnica.
Esperar pelo loader
Um script async pode ainda não ter corrido quando o código seguinte chama init(). Para dados pré-preenchidos usa um módulo de carga em vez da etiqueta estática, importado uma só vez no layout principal:
// /assets/quoting24-loader.js
const widgetScriptUrl =
"https://HOST_WIDGET/assets/widget/script.js?key=CHAVE_PUBLICA_WIDGET";
let widgetPromise;
export function loadWidget() {
if (window.Quoting24Widget) {
return Promise.resolve(window.Quoting24Widget);
}
if (widgetPromise) return widgetPromise;
widgetPromise = new Promise((resolve, reject) => {
const script = document.createElement("script");
script.id = "quoting24-widget-script";
script.src = widgetScriptUrl;
script.async = true;
script.onload = () => {
if (window.Quoting24Widget) resolve(window.Quoting24Widget);
else {
script.remove();
reject(new Error("A API do widget não está disponível"));
}
};
script.onerror = () => {
script.remove();
reject(new Error("Não foi possível carregar o widget"));
};
document.body.appendChild(script);
}).catch((error) => {
widgetPromise = undefined;
throw error;
});
return widgetPromise;
}
import { loadWidget } from "/assets/quoting24-loader.js";
const widget = await loadWidget();
widget.init({
external_id: "52",
company_name: "Ricambi Stella S.r.l.",
name: "mario.rossi",
phone: "+393331234567",
email: "amministrazione@ricambi-stella.example",
});
Importa o módulo a partir do bundler, ou carrega o ficheiro de entrada com <script type="module" src="/assets/assistencia.js"></script>. Para o modo incorporado acrescenta &mode=embedded&target=chat-assistencia ao URL e monta primeiro o contentor.
loadWidget() só indica que a API JavaScript está disponível. init() devolve void: põe o perfil em fila se o iframe não estiver pronto e não espera pela sessão. Para o resultado usa isReady() e hasSessionError().
init() substitui o perfil guardado. Não o funde com o anterior. Passa todos os campos que devam permanecer.
Uma mudança de página numa SPA não exige um script novo nem um reset(). Na mudança de pessoa ou de conta, e no logout, chama reset() antes do perfil novo: mudar só os campos não desliga a sessão de convidado anterior. Padrão completo: Login, logout e mudança de conta.
5. Como a empresa é associada ou criada
A Quoting24 executa este fluxo na inicialização, mesmo que o visitante ainda não tenha enviado uma mensagem:
- Com um
external_idnão vazio, procura uma empresa da mesma organização cujoweb_codeseja igual a esse valor - Se a encontrar, liga o contacto. O nome e o e-mail da empresa existente não mudam
- Se não a encontrar e também houver um
company_namenão vazio, cria a empresa comname = company_name,web_code = external_ide o e-mail se existir, e depois liga o contacto - Se não puder encontrar nem criar a empresa, continua com o perfil disponível. Se não chegar para um convidado novo, mostra o formulário. Erros de base de dados ou o limite de pedidos fazem falhar a inicialização
| Dados enviados | Situação na Quoting24 | Resultado |
|---|---|---|
external_id: "52", company_name: "Ricambi Stella S.r.l." |
Existe web_code = "52" |
Usa a empresa existente e não muda o nome |
| Os mesmos dados, mais um e-mail válido | Não existe web_code = "52" |
Cria a empresa com código web 52, denominação social e e-mail, e associa o contacto |
external_id: "52", name: "mario.rossi" |
Nenhuma correspondência | Inicia o convidado sem uma associação de empresa nova |
external_id: "52", sem outros dados |
Existe uma correspondência | Inicia o convidado associado à empresa, com o nome predefinido Visitatore |
external_id: "52", sem outros dados |
Nenhuma correspondência | Mostra o formulário de contacto |
company_name sem external_id, mais name |
Qualquer | Inicia o visitante. Não procura nem cria uma empresa |
A pesquisa não usa denominação social, e-mail, telefone, NIF nem companies.code. "052" e "52" são valores diferentes; os espaços de external_id não são retirados. Se importares o ficheiro antes, escreve em web_code o mesmo valor que o site vai enviar em external_id. Vê também Empresas → Código web.
Um convidado novo arranca se houver pelo menos um nome, um telefone, um e-mail válido ou um external_user_id, ou uma empresa encontrada ou criada através de external_id. init({}) e company_name sozinho não iniciam uma sessão.
Para um contacto já ligado, um código válido novo pode mudar a empresa. Omitir o código, ou enviar um que não se resolve, não apaga a associação anterior. A mudança de pessoa ou de conta exige reset().
Limites
web_code não é único. Com várias correspondências, a inicialização pública toma a primeira por data de criação crescente. Pedidos simultâneos que ainda não encontram a empresa podem criar mais do que uma: a criação não é atómica e não substitui uma importação ou uma sincronização a partir do ERP.
A criação implícita está limitada a 20 tentativas por janela de 60 segundos e endereço IP, no processo de backend que trata o pedido. Acima do limite a inicialização falha com TOO_MANY_REQUESTS: tenta de novo com espera, sem ciclos contínuos de init().
Os dados saem do browser e o visitante pode alterá-los. A ligação não prova a pertença à empresa e não concede o histórico da empresa. Envia company_name só se quiseres permitir esta criação pública. Para atualizar empresas já existentes usa as ferramentas da Quoting24 ou uma integração de ERP autorizada.
O e-mail da inicialização pública só fica na empresa nova. Não é escrito no contacto e não atualiza uma empresa já existente. Um telefone já usado por outro contacto não junta contactos nem chats.
6. Comportamento no site
| Situação | Comportamento esperado |
|---|---|
| Primeiro visitante, só script | Botão, depois formulário, depois chat |
init() com perfil suficiente |
Formulário omitido |
external_id já presente como web_code |
Contacto associado; nome e e-mail da empresa inalterados |
external_id novo com company_name |
Empresa criada e contacto associado |
Código novo e nome, sem company_name |
Chat sem empresa nova |
| Só código novo | Formulário de contacto |
| Só denominação social e nome | Nenhuma pesquisa nem criação por nome |
| Recarregamento no mesmo browser | Sessão de convidado retomada, se o armazenamento estiver disponível |
| Outro browser ou dispositivo | Sessão de convidado nova |
| Fora de horário | Banner fora de horário; a composição continua utilizável |
| Telemóvel, botão flutuante | O chat pode ocupar o viewport |
Anexos: PDF, DOC, DOCX, JPG/JPEG, PNG. Máximo de 10 MiB por ficheiro e 100 MiB de anexos referenciados por conversa.
7. Controlos úteis
Quando o botão flutuante está visível podes ligar um botão do site a window.Quoting24Widget?.open().
| Método | Uso |
|---|---|
init(profile) |
Define ou substitui o perfil atual |
open() / close() / toggle() |
Só widget flutuante. Fechar não é um logout |
isReady() |
Sessão de visitante iniciada. Continua falso no formulário de contacto |
hasSessionError() |
Erro de sessão assinalado pelo iframe |
reset() |
Apaga perfil, sessão local, credencial de convidado guardada e não lidos desta instância |
dispose() |
Desmonta a interface e os listeners. Não apaga a credencial de convidado guardada nem o objeto API global |
Não esperes por isReady() para um convidado novo abrir o formulário. Não há um evento público de disponibilidade. Estes indicadores não descrevem todo o estado da rede.
Lista de verificação antes da entrada em produção
- [ ] Host e chave do mesmo ambiente
- [ ] Domínios do site e do staging na lista, só como nomes de host
- [ ] Logótipo, cor, saudação, boas-vindas e fora de horário verificados
- [ ] Browser novo, só script: formulário, mensagem, ticket na Quoting24
- [ ]
external_idjá emweb_code: associação, ficha da empresa inalterada - [ ] Código novo com
company_name: empresa criada com esse código web - [ ] Código novo sem
company_name: nenhuma empresa criada - [ ] E-mail vazio, ID numérico ou denominação social demasiado longa: payload rejeitado, a corrigir
- [ ] Recarregamento e navegação SPA: uma só instância, sessão de convidado conservada
- [ ] Mudança de conta:
reset()de imediato, respostas tardias descartadas - [ ] Telemóvel: composição utilizável
- [ ] Domínio não autorizado: widget rejeitado
Problemas frequentes: Resolução de problemas.