Passa’l reuneix els jocs de paraules en català i deixa que cadascú es faci una rutina diària. Si has fet un joc, pots entrar al catàleg i connectar-lo amb Passa’l de dues maneres, segons fins on vulguis arribar.
Tria el tipus d’integració
Integració bàsica
Botó «Afegir a la rutina»
Un botó al teu web perquè la gent afegeixi el joc a la seva rutina amb un clic. Dues línies, i ja està.
Has de configurar: només l’identificador del teu joc.
Integració avançada
Integració amb resultats
El joc torna la persona a la seva rutina en acabar, Passa’l apunta que l’ha fet i tu reps estadístiques de les partides.
Has de configurar: l’identificador del joc i, un sol cop, quines dades envia. Opcional: un secret al teu servidor perquè els resultats surtin verificats.
La integració avançada inclou el botó de la bàsica: no cal triar-ne una i després refer-ho. Pots començar pel botó i passar a l’avançada quan vulguis.
1. Registra el joc
És el primer pas de les dues integracions: sense joc aprovat, l’identificador no porta enlloc.
- Registra el joc. Cal un compte de Passa’l. Et demanem el nom, una descripció curta, l’adreça on es juga, la periodicitat, la mecànica i les plataformes.
- Verifica el domini. Demostres que el joc és teu (com es fa).
- Esperes la revisió. Una persona de l’equip mira el joc i et respon. Si cal, et demana canvis.
- Ja tens l’identificador. Quan s’aprova, el joc surt al catàleg i a «Els teus jocs» tens el codi del botó, ja amb el teu identificador.
Si el teu joc ja surt al catàleg de Passa’l, no cal que el registris de nou: tria «Ja és al catàleg» i verifica el domini. Fins que no ho facis no veuràs ni podràs canviar res del joc; quan ho facis, passa a ser teu tal com és, i la resta va igual.
2. Integració bàsica: el botó «Afegir a la rutina»
Són dues línies: un enllaç i un petit script de Passa’l. L’script canvia l’enllaç pel botó oficial, de manera que el text, el logo i l’estil els posem nosaltres i no es poden canviar des del teu web. Si l’script no carrega, l’enllaç continua funcionant.
El codi
<!-- Passa’l · botó «Afegir a la rutina». L’únic que has de configurar és l’identificador del teu joc: sinonimot -->
<a class="passal-button" href="https://passal.cat/afegir/sinonimot" data-theme="auto">Afegir a la rutina</a>
<script async src="https://passal.cat/embed/v1.js"></script>Què has de configurar
sinonimot: l’identificador del teu joc. A «Els teus jocs» el codi ja el porta posat.data-theme:lightper a pàgines clares,darkper a fosques oautoperquè segueixi el sistema de qui visita (opcional).
No cal res més: ni claus, ni servidor, ni cap altra configuració.
Així es veu
L’exemple és Sinonimot, i el botó de sota és el de debò: si el prems, l’afegeixes a la teva rutina. El contorn és sempre taronja, i el text i la icona s’adapten a la teva pàgina.
Què fa per darrere
Qui el prem arriba a una pàgina de Passa’l amb el teu joc i tres camins: afegir-lo directament sense compte (la rutina es queda en aquell dispositiu), iniciar sessió o crear un compte perquè la rutina el segueixi a tot arreu. En acabar, pot tornar al teu joc. Si l’identificador no correspon a cap joc aprovat, la pàgina ho diu i no afegeix res.
Si el teu web té una política de seguretat de continguts (CSP), ha de permetre script-src https://passal.cat i frame-src https://passal.cat.
3. Integració avançada: amb resultats
Un joc integrat fa més que un botó: quan Passa’l hi envia algú, el joc el torna a la rutina amb un botó oficial, Passa’l apunta que l’ha fet (sense preguntar-ho) i el joc pot enviar el resultat de la partida. Quan l’equip aprova la integració i et torna el primer resultat, el joc surt al catàleg amb la insígnia «Amic de Passa’l». El botó sol (la integració bàsica) no porta insígnia. Si algú arriba al teu joc per un altre camí, el mateix botó fa de botó d’«Afegir a la rutina»: no cal que el teu joc sàpiga d’on ve qui juga.
Què cal fer
- Declara les dades. A «Els teus jocs», a la pàgina d’integració del joc, avises de quines dades enviarà (punts, durada, intents… i fins a cinc mètriques pròpies). Només cal fer-ho un cop.
- Enganxa el codi. La mateixa pàgina te’l dona ja amb el teu identificador.
- Prova i espera la revisió. Passa’l comprova un resultat d’exemple i, quan tot quadra, l’equip aprova la integració.
El codi
El codi té dues parts: la del web, sempre, i la del servidor, només si vols que els resultats surtin signats (ho explico més avall). Al web tries un dels dos fragments, segons si signes els resultats o no:
<!-- Passa’l · integració. L’únic que has de configurar és data-game, l’identificador del teu joc: sinonimot -->
<script>
window.passalReady = (Passal) => {
// 1. En arribar: qui juga ve de Passa’l? { active, date, code }
const launch = Passal.launch();
// 2. Quan el joc acaba: el botó oficial, construït amb el que li passes.
// Canvia els valors d’exemple pels de la partida que s’acaba de jugar.
// Només `state` és obligatori; la resta és el que declara el teu esquema de resultats.
Passal.returnButton('#passal-slot', {
state: 'completed', // 'completed' | 'skipped'
edition: '2026-10-26', // a stable id of today's puzzle
score: 120, maxScore: 150,
difficulty: 'hard',
durationSeconds: 84,
attempts: 3,
custom: { streak: 7 },
theme: 'auto',
});
};
</script>
<script async src="https://passal.cat/embed/v1.js" data-game="sinonimot"></script>
<div id="passal-slot"></div><!-- Passa’l · integració amb resultats signats pel servidor. Identificador del teu joc: sinonimot -->
<script>
window.passalReady = (Passal) => {
const launch = Passal.launch();
// L’ID de sessió de Passa’l: només hi és si la visita ve de Passa’l.
const sessionId = launch.code;
// Crida-la quan el teu joc acabi, amb el TEU identificador de la partida (playId).
// Si la visita no ve de Passa’l no hi ha sessionId ni res a signar:
// llavors el botó només afegeix el joc a la rutina.
window.onGameFinished = async (playId) => {
let result = { state: 'completed' };
let signature;
if (launch.active) {
// 1. Demana al TEU servidor el resultat i la seva signatura. Li dones dues coses:
// playId, el teu identificador, per trobar-ne el resultat;
// sessionId, l’ID de sessió de Passa’l, que el servidor només signa.
// Són els mateixos noms que llegeix el servidor a req.body.
const response = await fetch('/api/passal-result', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ playId, sessionId }),
});
({ result, signature } = await response.json());
}
// 2. Passa les dues coses al botó. La signatura no forma part del resultat: va al costat.
Passal.returnButton('#passal-slot', { ...result, signature, theme: 'auto' });
};
};
</script>
<script async src="https://passal.cat/embed/v1.js" data-game="sinonimot"></script>
<div id="passal-slot"></div>Què has de configurar
data-game="sinonimot": l’identificador del teu joc. A «Els teus jocs» el codi ja el porta posat.- Els valors de
returnButton(state,score…): els de la partida que acaba de fer qui juga. Nomésstateés obligatori.
No cal res més amb el primer fragment: no hi ha cap clau ni servidor. Signar els resultats amb el teu servidor (el segon fragment) és opcional.
Què fa per darrere
L’script de sempre porta ara l’identificador del joc (data-game) i un objecte Passal. Passal.launch() diu si qui arriba ve de Passa’l; Passal.returnButton() dibuixa el botó amb les dades que li passes. Posa la definició de passalReady abans de l’script, que és asíncron.
Quan Passa’l envia algú al teu joc, l’adreça porta un ID de sessió: un identificador d’un sol ús que només diu «aquesta visita ve de Passa’l», mai qui és la persona. No l’has de tractar tu: la biblioteca el llegeix sola.
Si fas servir un empaquetador, import Passal from 'https://passal.cat/embed/v1.mjs' dona el mateix objecte; llavors l’identificador va a { game } en comptes de data-game. I si no vols escriure JavaScript, posa un <div data-passal-return data-game="…"> i crida Passal.result({…}).
Les dades
Només state és obligatori. La resta són camps estàndard (edition, score i maxScore, difficulty, durationSeconds, attempts) i fins a cinc mètriques pròpies a custom, que declares a «Els teus jocs» amb el tipus, el rang i la unitat de cadascuna. A la mateixa pàgina declares quins camps estàndard envia el teu joc (punts, durada, intents), i si els punts tenen un màxim. Passa’l tria el gràfic segons el tipus i només en dibuixa dels camps que declares, així que no cal que en dibuixis cap; si declares nivells de dificultat, també compara les xifres per nivell. Qui juga veu els seus resultats amb els mateixos gràfics a «El teu recorregut». No hi ha text lliure: una mètrica no pot dur dades personals.
Resultats verificats (opcional)
A la pàgina d’integració del teu joc tries com enviarà els resultats, i ho pots canviar quan vulguis (caldrà tornar a provar i a revisar).
- Des del navegador (el primer fragment del web): no cal servidor i no signes res, però qui juga pot modificar el que envia. Les estadístiques es mostren igualment, amb l’avís que són dades declarades i no verificades.
- Des del servidor (el segon fragment del web, més el del servidor): el teu servidor signa cada resultat amb un secret. Passa’l sap que ningú no l’ha modificat («Detectat») i les seves mètriques compten a les estadístiques.
Si tries el servidor, la signatura no la calcula el teu web: va del teu servidor al botó, passant pel navegador. Hi surten tres identificadors, i és fàcil confondre’ls:
- L’identificador del teu joc (
data-game): el que Passa’l dona al teu joc al catàleg. És sempre el mateix. - L’ID de sessió de Passa’l (
Passal.launch().code; als fragments,sessionId): és nostre. Passa’l l’afegeix a l’adreça cada cop que envia algú al teu joc, és d’un sol ús i no diu qui és la persona. Tu no n’has de treure res: només el signes juntament amb el resultat. - L’identificador de la partida (
playId): és teu. El teu servidor el fa servir per trobar la partida i el seu resultat; Passa’l no el veu mai.
La signatura fa aquest recorregut, en tres passos:
- Passa’l envia qui juga al teu joc amb l’ID de sessió a l’adreça. El teu web el llegeix amb
Passal.launch().code. - Quan el joc acaba, el teu web demana el resultat al teu servidor. Li envia l’ID de sessió de Passa’l i el teu identificador de la partida. El servidor busca la partida amb el teu identificador, construeix el resultat amb el que ell en sap (mai amb el que digui el navegador), el signa amb el secret i l’ID de sessió, i respon amb el resultat i la signatura.
- El teu web passa les dues coses al botó:
Passal.returnButton('#passal-slot', { ...result, signature }). El botó envia a Passa’l el resultat, l’ID de sessió i la signatura, i Passa’l la comprova amb el secret del teu joc.
Per això el secret no surt mai del servidor: el navegador només veu el resultat i la signatura que ja li donen feta. Una signatura incorrecta es refusa, no es degrada a «sense signar».
Sense signatura, el resultat el pot escriure qui juga: serveix per al seu historial, però no entra a les estadístiques d’un joc que integra des del servidor. Si la visita no ve de Passa’l no hi ha codi ni res a signar, i el botó només afegeix el joc a la rutina: el teu web no ha de demanar res al servidor.
El codi del servidor
El del web és el segon fragment de «El codi»; aquest és el que va al teu servidor, tot en un: la funció que signa i la ruta que respon al web.
// 1. La funció que signa. L’únic que has de configurar és el secret (PASSAL_SECRET).
const { createHmac } = require('node:crypto');
// El mateix JSON per a les mateixes dades: les claus de cada objecte, ordenades.
const canonical = (value) =>
Array.isArray(value) ? `[${value.map(canonical).join(',')}]`
: value && typeof value === 'object'
? `{${Object.keys(value).filter((key) => value[key] !== undefined).sort()
.map((key) => `${JSON.stringify(key)}:${canonical(value[key])}`).join(',')}}`
: (JSON.stringify(value) ?? 'null');
// L’únic que has de configurar: el secret que et mostra Passa’l, com a variable d’entorn PASSAL_SECRET del teu
// servidor. Mai no el posis a la pàgina web.
// result: el que passes a Passal.returnButton, sense `signature` ni `theme`.
// sessionId: l’ID de sessió de Passa’l (Passal.launch().code), que la teva pàgina envia al teu servidor.
const sign = (result, sessionId, secret = process.env.PASSAL_SECRET) =>
createHmac('sha256', secret).update(`result|${sessionId}|${canonical(result)}`).digest('base64url');
// 2. La ruta que respon al teu web. Adapta resultOfGame al teu joc.
app.post('/api/passal-result', express.json(), (req, res) => {
// req.body és el que t’envia el TEU web: les dues coses del fetch del fragment del web.
// playId: el teu identificador de la partida, per trobar-ne el resultat.
// sessionId: l’ID de sessió de Passa’l (launch.code). No n’has de treure res, només signar-lo.
const { playId, sessionId } = req.body;
// El resultat surt del que sap el TEU servidor de la partida, mai del que digui la pàgina:
// això és el que la signatura garanteix.
const result = resultOfGame(playId); // p. ex. { state: 'completed', score: 120, custom: { streak: 7 } }
res.json({ result, signature: sign(result, sessionId) });
});Si el teu servidor no és Node.js
La signatura és un HMAC-SHA256 amb el secret sobre el text result|<ID de sessió>|<JSON>, on <ID de sessió> és l’ID de sessió de Passa’l tal com el dona Passal.launch().code i <JSON> és el resultat amb les claus ordenades alfabèticament a tots els nivells, sense espais i sense els camps buits. El resultat que signes ha de ser exactament el que passes al botó, sense signature ni theme.
La signatura s’escriu en base64url (RFC 4648 §5): com el base64 de sempre, però amb - i _ en lloc de + i /, i sense els = del final. A Node és .digest('base64url'); en altres llenguatges cal fer la conversió.
Què has de configurar
PASSAL_SECRET: el secret del teu joc, com a variable d’entorn al servidor. El veus sempre a la pàgina d’integració, i el pots canviar quan vulguis (l’anterior deixa de valer).
No cal res més. El secret no ha de sortir mai del teu servidor: si el poses al web, qualsevol jugador el pot copiar i inventar-se resultats.
Verificació del domini
Per aprovar un joc és obligatori demostrar que controles el seu domini. Quan registres el joc, et donem un codi i tries com ensenyar-lo; amb una de les dues maneres n’hi ha prou:
- Un registre DNS TXT. Al DNS del teu domini, crea un registre de tipus
TXTamb el nom_passal-verify.el-teu-domini.cati el valorpassal-verify=<el teu codi>. També val al domini principal si el joc és en un subdomini. Els canvis de DNS poden trigar una estona. - Un fitxer al teu web. Publica
https://el-teu-domini.cat/.well-known/passal-verify.txtamb una línia que diguipassal-verify=<el teu codi>, amb https i sense redireccions.
Les comprovem totes dues quan ho demanes i un altre cop en el moment d’aprovar el joc, així que cal deixar la prova publicada. Si canvies el domini del joc, cal tornar-lo a verificar.
Revisió i estadístiques
Què mirem a la revisió
- Que sigui un joc de paraules o de llengua, en català o pensat per a qui el parla.
- Que l’adreça funcioni i es pugui jugar sense haver de pagar per entrar-hi a mirar.
- Que la descripció digui què és i no prometi el que no fa.
- Que el domini sigui teu.
Un cop publicat, pots editar el joc. Els canvis no surten fins que els revisem; mentrestant es veu la versió aprovada.
Estadístiques
Quan el joc és aprovat, a «Els teus jocs» tens un botó d’estadístiques: quantes persones el tenen a la rutina, quantes l’han obert des de Passa’l i quantes l’han marcat com a fet, els darrers 30 dies. Són només nombres de persones, mai qui són. Si en són menys de 5, no te’n diem la xifra, perquè podria assenyalar algú concret. «Obert», «fet» i els resultats compten qui juga amb compte i qui juga sense; «a la rutina» i els afegits i retirats només compten comptes, perquè la rutina de qui no en té només és al seu dispositiu.
Què passa amb les dades
El botó és una pàgina de passal.cat dins un iframe: quan es carrega, el navegador demana el botó i l’script a Passa’l, com amb qualsevol contingut incrustat. Passa’l no hi posa cookies, no hi guarda res al navegador i no hi compta visites. Passa’l no envia cap dada de qui el prem al teu web.
Amb la integració avançada, el resultat va al fragment (#) de l’adreça de tornada, que el navegador no envia a cap servidor. Passa’l no dona al teu joc cap dada de qui hi juga: l’ID de sessió és opac, d’un sol ús i no porta ni compte ni identificador. Les estadístiques que veus són agregats, i no es mostren per sota de 5 persones. Amb la integració bàsica, la rutina d’un joc de tercers es marca a mà: la persona decideix quan l’ha fet, i Passa’l no sap què ha passat dins el teu joc.

