Chrome MV3 extension for importing quizzes and study content from supported web apps into Testownik. The first supported source is NotebookLM Quiz App.
- WXT + React + TypeScript + Tailwind v4 extension.
- shadcn-style UI copied to Base UI primitives, using Testownik design tokens.
- Toolbar popup for auth status, login/logout, and opening Testownik.
- NotebookLM content scripts:
- top frame injects
Dodaj do Testownikainto the Studio App footer, - sandbox frame reads quiz JSON from
app-root[data-app-data], - iframe sends quiz data to the top frame with
postMessage.
- top frame injects
- Background service worker handles OAuth2 Authorization Code + PKCE, token
refresh, storage, and
POST /api/quizzes/. - One-click import: unauthenticated users sign in first, then the quiz is created directly.
- Imported questions are marked
is_ai_generated: true.
Source integrations are isolated under src/sources/<source>/.
src/sources/types.ts: shared adapter contract.src/sources/notebooklm/adapter.ts: source identity and mapper binding.src/sources/notebooklm/mapping.ts: NotebookLM JSON to Testownik quiz body.src/sources/notebooklm/footer.ts: NotebookLM-specific footer anchor logic.src/sources/notebooklm/types.ts: NotebookLM payload/message types.src/lib/dom.tsx: source-neutral shadow DOM mounting.src/components/AddToTestownikButton.tsx: source-neutral import button.src/entrypoints/background.ts: source-neutral OAuth/token/API bridge.
To add another source later, add a new src/sources/<source>/ folder, create a
new content entrypoint for that site, implement SourceImportAdapter, provide a
mount-target finder, and call watchSourceButtonMount.
QuizViewSetaccepts OAuth2 bearer tokens in addition to JWT/session auth.- OAuth tokens need
quizzes:writefor unsafe quiz writes. - JWT/session quiz creation still works without OAuth scopes.
CORS_ALLOWED_ORIGINSmust include the extension origin:
CORS_ALLOWED_ORIGINS=https://testownik.solvro.pl,chrome-extension://<EXTENSION_ID>- OAuth Applications now have optional Testownik metadata with
logo_uri; the logo is returned by the consent and authorized-apps APIs.
Use one target per build:
VITE_TESTOWNIK_API_BASE_URL=https://api.testownik.solvro.pl
VITE_TESTOWNIK_FRONTEND_URL=https://testownik.solvro.pl
VITE_TESTOWNIK_OAUTH_CLIENT_ID=<public OAuth client id>Create a django-oauth-toolkit app for the extension:
- Client type:
Public - Grant type:
Authorization code - Redirect URI:
https://<EXTENSION_ID>.chromiumapp.org/ - Scopes:
quizzes:write - Logo URI: set in the Application admin inline metadata
pnpm install
pnpm devLoad .output/chrome-mv3 in chrome://extensions. After reloading the
extension, refresh any open supported source page.
pnpm typecheck
pnpm build
pnpm zipThe unpacked extension is in .output/chrome-mv3; the store zip is in .output.
- Finish OAuth app registration in local and production admin.
- Build the production extension and load it once to confirm the final extension ID.
- Add
chrome-extension://<EXTENSION_ID>to backendCORS_ALLOWED_ORIGINS. - Set the OAuth redirect URI to
https://<EXTENSION_ID>.chromiumapp.org/. - Run end-to-end import from NotebookLM to production Testownik.
- Create the Chrome Web Store item: screenshots, icon, description, privacy answers, single purpose, and host permission justification.
- Add GitHub repository variables and secrets:
VITE_TESTOWNIK_API_BASE_URLVITE_TESTOWNIK_FRONTEND_URLVITE_TESTOWNIK_OAUTH_CLIENT_IDCHROME_EXTENSION_IDCHROME_CLIENT_IDCHROME_CLIENT_SECRETCHROME_REFRESH_TOKEN
- Publish a GitHub release or run
Publish to Chrome Web Storemanually. - Wait for Chrome Web Store review, then verify the published install.
- Button appears once in the NotebookLM Studio App footer.
- Button stays inline and truncates instead of overflowing.
- Clicking creates the quiz directly.
- Expired tokens refresh silently.
- Missing
quizzes:writeshows an error. - Created Testownik quiz has correct answers, explanations, title, and AI-generated question flags.