QR Codes
QR codes are a companion surface for Dub short links: they let a link be shared offline or in visual placements while still resolving through the same attribution platform. In Dub’s product documentation, QR customization is presented as part of link creation and link editing, with controls for visual design and logo behavior. In the repository, the QR feature is represented by two different layers: an OpenAPI operation that exposes QR retrieval to API clients, and a React/TypeScript rendering module that turns a value into a canvas-backed QR image with styling and optional embedded image support.
Sources: apps/web/lib/openapi/qr/index.ts, apps/web/lib/qr/index.tsx
Purpose and Scope
This page explains the QR code workflow at the level a developer needs when integrating with Dub or extending the QR implementation. The API surface is intentionally small: clients request a QR image for a link through the QR OpenAPI path, and the response is a PNG image rather than JSON metadata. The rendering layer is richer because QR design is a visual concern. It accepts a target value, sizing, colors, error-correction level, margin, and image settings, then draws the QR code into a canvas while preserving scan reliability through module excavation when an image is placed on top.
The practical distinction is important. The API module describes the public contract that generated docs and SDKs can expose. The rendering module describes how Dub can produce and preview QR codes in application UI or download flows. A user may think of QR codes as a feature of links, but the code splits the concern into a retrieval endpoint and reusable QR primitives. That split keeps API documentation stable while allowing the UI implementation to evolve its drawing logic, dot styles, marker styles, logos, and utility helpers independently.
Sources: apps/web/lib/openapi/qr/index.ts, apps/web/lib/qr/index.tsx
Relevant Source Files
- apps/web/lib/openapi/qr/index.ts — Defines the QR Codes OpenAPI operation, including the GET path, query schema, PNG response type, operation id, Speakeasy name override, and shared error responses.
- apps/web/lib/qr/index.tsx — Implements the QR canvas renderer, exports QR-related types and utilities, imports default constants, generates QR modules, applies colors and margins, and optionally renders an image into the QR code.
These files should be read together. The OpenAPI module tells external consumers how to retrieve a QR code, while the renderer shows the internal mechanics available to Dub’s web application. The OpenAPI operation imports its query validation from the QR Zod schema and attaches shared error responses, so it participates in the same generated API documentation system as the rest of Dub’s public endpoints. The renderer imports constants, types, and utility helpers from the local QR package area, indicating that QR rendering is treated as a dedicated subsystem rather than an incidental component.
Sources: apps/web/lib/openapi/qr/index.ts, apps/web/lib/qr/index.tsx
API Surface
The QR API is represented by a single OpenAPI path: GET /qr. Its operation id is getQRCode, its Speakeasy name override is get, its summary is Retrieve a QR code, and its description says it retrieves a QR code for a link. Request parameters are supplied through the query string and validated by getQRCodeQuerySchema. A successful response uses the image/png content type with a string schema, which means API clients should handle the response as image data rather than as a JSON object.
| Contract item | Source-level name | Behavior |
|---|---|---|
| Path | /qr | Public QR retrieval route in the OpenAPI paths object |
| Method | GET | Retrieves an existing/generated QR code for a link |
| Operation id | getQRCode | Stable OpenAPI operation identifier |
| SDK naming hint | x-speakeasy-name-override: get | Guides generated SDK naming |
| Query validation | getQRCodeQuerySchema | Defines accepted query parameters for QR retrieval |
| Success content type | image/png | Returns QR image content |
| Error handling | openApiErrorResponses | Adds the shared API error response set |
| Tag | QR Codes | Groups the endpoint in generated API documentation |
Because the response is image/png, consumers should plan their integration around binary/image handling. In a browser, that may mean using the route as an image source or fetching a blob. In server-side code, it may mean streaming the response to storage, returning it from another route, or attaching it to a generated asset. The OpenAPI definition does not describe QR mutation operations here; customization is primarily part of link creation/editing in the product experience, while this API path is scoped to retrieval.
Sources: apps/web/lib/openapi/qr/index.ts
Rendering Components
The QR rendering module exports QRCodeCanvas as the canvas implementation and re-exports QR-related types and utilities for adjacent code. QRCodeCanvas accepts QRPropsCanvas and destructures common rendering options: value, size, level, background color, foreground color, margin, style, imageSettings, and remaining canvas props. Defaults come from local constants such as DEFAULT_SIZE, DEFAULT_LEVEL, DEFAULT_BGCOLOR, DEFAULT_FGCOLOR, and DEFAULT_MARGIN. This makes the component usable with minimal input while still allowing callers to control the visual design.
At render time, QRCodeCanvas uses qrcodegen.QrCode.encodeText to convert the supplied value into a matrix of QR modules. The selected error-correction level is mapped through ERROR_LEVEL_MAP, and the final drawing area is computed from the number of QR cells plus the configured margin. The component then calculates optional image placement with getImageSettings. If an image is available and valid, and excavation information exists, excavateModules removes QR modules underneath the image so the embedded logo or graphic can be drawn cleanly without simply painting over data cells.
The canvas drawing path is optimized for modern browser support but retains a fallback. When Path2D is supported, the renderer fills a generated path from generatePath, which compactly represents the QR modules. Without Path2D, it iterates through each row and cell and fills individual one-by-one rectangles for active modules. After the QR body is drawn, the optional image is drawn at the calculated coordinates and dimensions. The implementation also accounts for devicePixelRatio, scaling the canvas backing size for sharper output on high-density displays.
Sources: apps/web/lib/qr/index.tsx
Implementation Details
Several details in the renderer are worth preserving when changing QR behavior. The component tracks the hidden image element with a ref and resets its image-loaded state when the image source changes. The hidden image uses alt text of QR code, display none styling, and an onLoad handler to notify React that the image is available. The current snippet does not rely on the state value directly in visible output, but setting state after load ensures the component can re-render after image loading and then draw the image into the canvas.
The module also imports style-related types such as DotStyle, MarkerBorderStyle, and MarkerCenterStyle, along with path helpers for rounded and square dots. The shown implementation begins a set of SVG string helpers for download, starting with a roundedRectPath helper. That indicates the QR package is not only a live canvas preview; it also contains lower-level drawing utilities that can support exported assets. When adding QR design options, prefer routing them through typed props and shared utility helpers rather than duplicating drawing math in product components.
Custom logo behavior should be treated as both a product and rendering concern. Product documentation explains that free users see the Dub logo by default, paid plans can hide or customize logos, and workspace/domain logo precedence affects which image is used. The renderer itself is lower-level: it receives imageSettings and draws whatever validated image source and placement it is given. That separation lets plan checks, workspace settings, and domain settings live outside the drawing primitive, while the primitive remains focused on producing a valid QR graphic.
Sources: apps/web/lib/qr/index.tsx
System-to-Code Mapping
| User or developer task | Code surface | What to inspect |
|---|---|---|
| Retrieve a QR code through the API | apps/web/lib/openapi/qr/index.ts | qrCodePaths, getQRCode, response content type, query schema import |
| Generate API docs or SDK methods | apps/web/lib/openapi/qr/index.ts | operationId, x-speakeasy-name-override, tags, openApiErrorResponses |
| Preview a QR code in UI | apps/web/lib/qr/index.tsx | QRCodeCanvas props, defaults, canvas drawing effect |
| Customize QR appearance | apps/web/lib/qr/index.tsx | bgColor, fgColor, margin, size, level, imageSettings |
| Embed a logo or image | apps/web/lib/qr/index.tsx | getImageSettings, excavateModules, hidden image ref, drawImage |
| Extend rendering utilities | apps/web/lib/qr/index.tsx | exported types, exported utils, path generation helpers |
A safe implementation path starts with the level of abstraction the change belongs to. If the goal is to expose a new public QR retrieval option, begin with the OpenAPI query schema used by getQRCode and make sure the generated operation still returns image/png with consistent error behavior. If the goal is visual rendering, begin with QRCodeCanvas and the QR utilities. Avoid coupling plan or workspace rules directly into the renderer; instead, compute the appropriate image settings before passing them to the QR component.
Sources: apps/web/lib/openapi/qr/index.ts, apps/web/lib/qr/index.tsx
Next Steps
For API consumers, the next step is to treat GET /qr as an image-producing endpoint and wire the response into the place where the QR asset will be displayed, downloaded, or stored. For application developers, the next step is to inspect the QR props and utility exports before adding new design options, because the renderer already centralizes defaults, error-correction mapping, image excavation, Path2D drawing, and canvas scaling. For product work, keep the distinction between customization policy and rendering mechanics clear so plan checks and domain/workspace logo precedence remain outside the drawing primitive.
Related pages: links-and-short-urls, manage-links, api-reference-introduction, qr-tags-embed-tokens-api