Vorschau
Code zum Einbinden
Füge den Code an der Stelle deiner Seite ein, an der das Quiz erscheinen soll.
Gut zu wissen
- Nutzt deine Seite eine Content-Security-Policy, ergänze bei script-src: https://www.qwissit.com
- Das Widget setzt keine Cookies und speichert nichts im Browser. Es lädt nur das Skript und die Fragen von Qwissit.
- Die Fragen wechseln automatisch. Um Farben oder Texte zu ändern, erzeuge hier einen neuen Code und ersetze den alten.
Optional: Einbindung über deine eigene Domain
Wenn du keine Anfragen an fremde Server möchtest, liefert dein Webserver das Quiz aus: Er reicht einen Pfad wie /qwissit/ an Qwissit weiter. Der Browser deiner Besucher spricht dann nur mit deiner Domain, Qwissit sieht nur die Adresse deines Servers. Die direkte Einbindung oben bleibt der einfache Standard.
1. Webserver einrichten: /qwissit/ auf https://www.qwissit.com/widget/v1/ weiterleiten, ohne Cookies, IP-Adresse und andere Angaben deiner Besucher.
nginx
location ^~ /qwissit/ {
proxy_pass https://www.qwissit.com/widget/v1/;
proxy_set_header Host www.qwissit.com;
proxy_ssl_server_name on;
proxy_set_header X-Forwarded-For "";
proxy_set_header X-Real-IP "";
proxy_set_header Cookie "";
proxy_set_header Referer "";
proxy_set_header User-Agent "qwissit-proxy";
proxy_hide_header Set-Cookie;
}Apache (mod_proxy, mod_ssl, mod_headers)
SSLProxyEngine On
<Location "/qwissit/">
ProxyPass "https://www.qwissit.com/widget/v1/"
ProxyAddHeaders Off
RequestHeader unset Cookie
RequestHeader unset Referer
RequestHeader set User-Agent "qwissit-proxy"
Header unset Set-Cookie
</Location>Caddy
handle_path /qwissit/* {
rewrite * /widget/v1{path}?{query}
reverse_proxy https://www.qwissit.com {
header_up Host {upstream_hostport}
header_up -X-Forwarded-For
header_up -Cookie
header_up -Referer
header_up User-Agent qwissit-proxy
header_down -Set-Cookie
}
}PHP (Shared Hosting)
Ohne Zugriff auf die Server-Konfiguration (Shared Hosting): Lade die PHP-Datei herunter, speichere sie als qwissit-proxy.php in deinem Webverzeichnis und nimm als Skript-Adresse /qwissit-proxy.php/qwissit-widget.js. Sie reicht nur die Dateien des Widgets weiter.
2. Im Code oben die Skript-Adresse ersetzen:
<script src="/qwissit/qwissit-widget.js" async></script>
3. Selbsttest: Der Aufruf mit deiner Domain muss 200 und content-type: text/javascript liefern. Ein 404 deutet auf einen Punkt unter „Wenn es nicht klappt“, eine HTML-Seite darauf, dass dein CMS die Anfrage übernommen hat.
curl -I https://example.org/qwissit/qwissit-widget.js
Danach im Browser mit den Entwickler-Werkzeugen (F12), Tab „Netzwerk“: Es darf keine Anfrage an www.qwissit.com erscheinen.
Wenn es nicht klappt
- nginx liefert 404: Regeln für statische Dateien wie location ~* \.(js|css)$ haben Vorrang vor einfachen Präfix-Regeln, dann sucht nginx qwissit-widget.js auf deinem Server. Darum steht im Snippet location ^~ /qwissit/ – das ^~ sorgt dafür, dass dieser Pfad immer weitergereicht wird.
- Änderungen wirken erst nach dem Neuladen: nginx -t && nginx -s reload, bei Apache apachectl configtest && systemctl reload apache2. In Docker mit einer einzeln eingebundenen Konfigurationsdatei sieht der Container nach dem Ersetzen der Datei (rsync, cp) weiter die alte Fassung – dann hilft nur ein Neustart des Containers (docker compose restart <dienst>).
- Apache: Die Module proxy, proxy_http, ssl und headers müssen aktiv sein (a2enmod proxy proxy_http ssl headers). Die Regeln gehören in die Server- bzw. VirtualHost-Konfiguration, nicht in die .htaccess. Geht bei dir nur die .htaccess, nimm die PHP-Datei.
- PHP-Datei: Sie muss wirklich im Webverzeichnis liegen (bei TYPO3 in public/), sonst übernimmt das CMS die Anfrage. Der Server muss den Pfad hinter der Datei (PATH_INFO) an PHP geben: bei Apache AcceptPathInfo On (bei vielen Hostern Standard), bei nginx in der PHP-Regel so:
location ~ \.php(/|$) { fastcgi_split_path_info ^(.+\.php)(/.*)$; fastcgi_param PATH_INFO $fastcgi_path_info; # … your usual fastcgi_pass / include fastcgi_params }
Optional: Ergebnisse fälschungssicher prüfen
Du willst auf deiner Website festhalten, dass jemand das Quiz geschafft hat – zum Beispiel um eine Lektion abzuhaken oder Punkte zu vergeben? Dann lässt du dir das Ergebnis von Qwissit bestätigen. So kann es niemand vortäuschen.
So läuft es ab
- Deine Seite gibt dem Quiz einen Einmal-Code mit, den sie sich merkt.
- Der Besucher löst das Quiz. Qwissit prüft jede Antwort selbst; falsch beantwortete Fragen kommen noch einmal, bis alle richtig sind.
- Am Ende bekommt deine Seite einen Nachweis, den nur Qwissit ausstellen kann, und schickt ihn an deinen Server.
- Dein Server fragt bei Qwissit nach, ob der Nachweis echt ist und zu deinem Code und Quiz passt. Erst dann speichert er das Ergebnis.
Was du einbaust
Zwei Stellen, beide in PHP. Deine Besucher müssen angemeldet sein (Session), denn das Ergebnis soll ja jemandem zugeordnet werden.
A) Auf der Seite mit dem Quiz: Dieser Block ersetzt das normale Snippet. Passe data-set und data-course an dein Quiz an – die Werte stehen im Code oben.
<?php
session_start(); // your visitors are signed in
$nonce = $_SESSION['quiz_nonce']['http'] ??= rtrim(strtr(base64_encode(random_bytes(16)), '+/', '-_'), '=');
?>
<div id="quiz" data-qwissit-widget data-set="12" data-course="13" data-lang="de"
data-verify="<?= $nonce ?>"></div>
<script src="https://www.qwissit.com/widget/v1/qwissit-widget.js" async></script>
<script>
document.getElementById('quiz').addEventListener('qwissit:finish', function (e) {
if (!e.detail.passed || !e.detail.token) return;
fetch('quiz-complete.php', {
method: 'POST',
credentials: 'same-origin',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: 'lesson=http&token=' + encodeURIComponent(e.detail.token)
}).then(function (r) {
if (r.ok) { /* done: e.g. show a tick */ }
});
});
</script>
B) Eine neue Datei quiz-complete.php im selben Ordner. Trag bei QUIZZES dieselben Werte für set und course ein und speichere das Ergebnis an der markierten Stelle so, wie es zu deiner Website passt.
<?php
// quiz-complete.php – checks the result with Qwissit and saves it only if everything matches
session_start();
const QUIZZES = ['http' => ['set' => 12, 'course' => 13]]; // same values as data-set / data-course
$lesson = (string)($_POST['lesson'] ?? '');
$token = (string)($_POST['token'] ?? '');
$quiz = QUIZZES[$lesson] ?? null;
$nonce = (string)($_SESSION['quiz_nonce'][$lesson] ?? '');
if (!$quiz || $nonce === '' || $token === '') { http_response_code(400); exit; }
$ch = curl_init('https://www.qwissit.com/widget/v1/verify');
curl_setopt_array($ch, [
CURLOPT_POST => true,
CURLOPT_POSTFIELDS => http_build_query(['token' => $token]),
CURLOPT_RETURNTRANSFER => true,
CURLOPT_TIMEOUT => 4,
]);
$r = json_decode((string)curl_exec($ch), true);
curl_close($ch);
if (!is_array($r)) { http_response_code(503); exit; } // Qwissit not reachable: save nothing
if (($r['valid'] ?? false) !== true
|| !hash_equals($nonce, (string)($r['nonce'] ?? ''))
|| (int)$r['set'] !== $quiz['set'] || (int)$r['course'] !== $quiz['course']) {
http_response_code(403); exit; // forged, already used, expired or another quiz
}
unset($_SESSION['quiz_nonce'][$lesson]); // the code counts only once
// ▶ save the result here, e.g. user + $lesson + date (+ $r['wrong'] = failed attempts)
header('Content-Type: application/json');
echo json_encode(['ok' => true]);
Die Datei speichert nur, wenn Qwissit den Nachweis bestätigt, er zu deinem Einmal-Code gehört und vom richtigen Quiz stammt. Danach ist der Code verbraucht, jedes Ergebnis zählt also nur einmal. Ist Qwissit gerade nicht erreichbar, wird nichts gespeichert – lass den Besucher es später noch einmal versuchen. Der Nachweis gilt eine Stunde.
Gut zu wissen
- Warum der Umweg über deinen Server? Das Widget meldet das Ende des Quiz zwar auch direkt im Browser (Ereignis qwissit:finish), aber das kann jeder mit etwas Technikwissen selbst auslösen. Für eine Anzeige reicht es, für Punkte, Zertifikate oder Freischaltungen nicht.
- Zeig das Quiz mit Einmal-Code nur angemeldeten Besuchern und lege für alle anderen keine Session an – sonst erzeugt jeder Bot eine.
- Schütze quiz-complete.php wie deine anderen Formulare: Anmeldung prüfen, nur Anfragen von deiner eigenen Seite annehmen, Zahl der Anfragen begrenzen.
- Nach einem Erfolg bekommt der Besucher beim nächsten Aufruf einen neuen Code und kann das Quiz wiederholen.
- Zum Testen: Ein ausgedachter Nachweis, derselbe Nachweis ein zweites Mal und der Nachweis eines anderen Quiz müssen abgelehnt werden.
Textbaustein für deine Datenschutzerklärung
Ein Vorschlag, den du an deine Seite anpassen kannst. Er ersetzt keine Rechtsberatung.
Direkt eingebunden
Auf dieser Website binden wir ein Quiz von Qwissit ein (www.qwissit.com). Beim Laden ruft dein Browser das Skript und die Fragen von www.qwissit.com ab; dabei wird deine IP-Adresse übertragen. Das Quiz setzt keine Cookies, speichert nichts in deinem Browser und speichert deine Antworten nicht. Rechtsgrundlage ist unser berechtigtes Interesse an einem interaktiven Lernangebot (Art. 6 Abs. 1 lit. f DSGVO). Mehr dazu: https://www.qwissit.com/datenschutz#widget
Über deine eigene Domain (Proxy)
Auf dieser Website binden wir ein Quiz von Qwissit ein. Skript und Fragen liefert unser eigener Server aus, der sie bei Qwissit abruft. Dein Browser verbindet sich dabei nicht mit Qwissit, und Qwissit erhält weder deine IP-Adresse noch Cookies oder andere Angaben über dich. Das Quiz setzt keine Cookies, speichert nichts in deinem Browser und speichert deine Antworten nicht. Mehr dazu: https://www.qwissit.com/datenschutz#widget