An open-source, browser-based chat interface for the Qwant Answer V2 API.
Built with React + Vite + TypeScript, powered by the official @qwant/answer SDK.
- Streaming answers — token-by-token rendering via SSE
- Source cards — clickable references with domain + title
- Related questions — clickable follow-up chips
- Conversation history — multi-turn context sent automatically
- Markdown rendering — full GFM support via
react-markdown - Custom sources — bypass Bloom search with your own URLs
- Domain filter — restrict answers to a single domain
- Dual theme — light / dark / system with localStorage persistence
- Fully configurable — API key, base URL, mode, query rewrite, and more
- Node.js ≥ 18
- An API key for the Qwant Answer V2 API
git clone https://github.com/Qwant/playground-answer-V2.git
cd playground-answer-V2
npm install
npm run devOpen http://localhost:5173 and enter your API key in the Settings panel (⚙️ top right).
npm run build
npm run previewThe included .github/workflows/deploy.yml automatically deploys to GitHub Pages on every push to main.
- Fork or clone this repository
- Go to Settings → Pages and set the source to GitHub Actions
- Push to
main— the workflow handles the rest
The VITE_BASE env var in the workflow is set to /playground-answer-V2/. Update it to match your repository name if you fork under a different name.
VITE_BASE=/playground-answer-V2/ npm run build
# Upload dist/ to any static hostAll settings are persisted to localStorage (API key uses sessionStorage).
| Setting | Description | Default |
|---|---|---|
| API Key | Bearer token for the Answer V2 API | — |
| Base URL | API base URL, useful for local dev | https://api.staan.ai/v2 |
| Domain filter | Restrict search to a single domain | — |
| Response length | short or long |
short |
| Markdown | Render response as Markdown | true |
| Related questions | Show follow-up question chips | false |
| Query rewrite | Rewrite query before search | true |
| Sources mode | search (fetch + rerank) or context (direct injection) |
search |
| Custom sources | Provide your own URLs, bypassing Bloom | — |
| Package | Role |
|---|---|
@qwant/answer |
Official SDK — streaming, SSE parsing, types |
| React 19 | UI framework |
| Vite 8 | Build tool |
| react-markdown | Markdown rendering |
| remark-gfm | GitHub Flavored Markdown |
src/
├── App.tsx # Root component — layout + header
├── types.ts # Shared TypeScript types
├── index.css # Global styles (CSS variables, dual theme)
├── components/
│ ├── ChatMessage.tsx # Individual message bubble
│ ├── ChatInput.tsx # Textarea + send/stop buttons
│ ├── EmptyState.tsx # Welcome screen
│ ├── Icons.tsx # Inline SVG icons
│ ├── RelatedQueries.tsx # Follow-up question chips
│ ├── SettingsDrawer.tsx # Side drawer — all configuration
│ └── SourcesList.tsx # Source cards grid
├── hooks/
│ ├── useChat.ts # Streaming logic via @qwant/answer
│ ├── useSettings.ts # Settings state + localStorage sync
│ └── useTheme.ts # Theme toggle + persistence
└── lib/
└── storage.ts # localStorage / sessionStorage helpers
MIT