A zero-cost, self-hosted dynamic QR code redirect system using Quarto, Python, GitHub Pages, and Markdown as a database. Update redirect destinations without regenerating QR codes!
- Static QR Codes: Generate once, use foreverβQR codes never change
- Dynamic Redirects: Update destinations by editing Markdown files
- Zero Cost: Fully hosted on GitHub Pages (free tier)
- Auto-Deploy: Push changes β GitHub Actions rebuilds site automatically
- No Server Required: Pure static site with client-side redirects
- Full Control: Own your data, own your infrastructure
- QR codes point to static URLs:
yourusername.github.io/repo/{slug} - Markdown files define redirects: Each file in
_redirects/contains aslugandtarget_url - Quarto renders redirect pages: Generates HTML with meta refresh and JavaScript redirects
- GitHub Actions auto-builds: Every commit triggers a site rebuild
- Users scan β redirect: QR code β static URL β instant redirect to current target
βββββββββββββββ ββββββββββββββββββββ βββββββββββββββββββ
β QR Code β --> β GitHub Pages β --> β Target URL β
β /menu β β /menu/index.htmlβ β example.com/... β
βββββββββββββββ ββββββββββββββββββββ βββββββββββββββββββ
Static Auto-rebuilt Editable in MD
.
βββ _quarto.yml # Quarto configuration
βββ _redirects/ # Markdown "database" of redirects
β βββ menu.qmd # Redirect: /menu β target_url
β βββ contact.qmd # Redirect: /contact β target_url
β βββ promo.qmd # Redirect: /promo β target_url
βββ _extensions/
β βββ redirect/
β βββ redirect.html # HTML template for redirects
β βββ _extension.yml # Extension config
βββ .github/
β βββ workflows/
β βββ publish.yml # GitHub Actions auto-deploy
βββ generate_qr_codes.py # Python script to generate QR codes
βββ requirements.txt # Python dependencies
βββ index.qmd # Homepage
βββ qr_codes/ # Generated QR code images (not in repo)
- GitHub account
- Python 3.8+ (for QR code generation)
- Git
# Clone this repository
git clone https://github.com/yourusername/Dynamic-QR-code-on-a-shoestring.git
cd Dynamic-QR-code-on-a-shoestring
# Create a virtual environment
python -m venv venv
source venv/bin/activate # On Windows: venv\Scripts\activate
# Install Python dependencies
pip install -r requirements.txt- Go to your repository on GitHub
- Navigate to Settings β Pages
- Under Source, select:
- Source: Deploy from a branch
- Branch:
gh-pages/root
- Click Save
- Go to Settings β Actions β General
- Scroll to Workflow permissions
- Select Read and write permissions
- Check Allow GitHub Actions to create and approve pull requests
- Click Save
Edit _redirects/menu.qmd:
---
title: "Redirecting to Menu..."
slug: menu
target_url: "https://example.com/your-actual-menu"
format:
html:
template: ../_extensions/redirect/redirect.html
---# Replace with your actual GitHub Pages URL
python generate_qr_codes.py https://yourusername.github.io/Dynamic-QR-code-on-a-shoestring
# QR codes will be saved to qr_codes/ foldergit add .
git commit -m "Initial setup with redirects"
git push origin mainGitHub Actions will automatically:
- Build your Quarto site
- Deploy to GitHub Pages
- Make redirects live in ~1-2 minutes
Visit: https://yourusername.github.io/Dynamic-QR-code-on-a-shoestring/menu
You should be redirected to your target_url!
Create _redirects/newslug.qmd:
---
title: "Redirecting..."
slug: newslug
target_url: "https://example.com/destination"
format:
html:
template: ../_extensions/redirect/redirect.html
---python generate_qr_codes.py https://yourusername.github.io/Dynamic-QR-code-on-a-shoestringgit add _redirects/newslug.qmd
git commit -m "Add newslug redirect"
git pushThe QR code at qr_codes/newslug.png is now permanentβprint it, share it, use it anywhere!
This is the magic: Change where a QR code points without regenerating it!
Edit _redirects/menu.qmd:
---
title: "Redirecting to Menu..."
slug: menu
target_url: "https://example.com/new-menu-location" # β Changed!
format:
html:
template: ../_extensions/redirect/redirect.html
---git add _redirects/menu.qmd
git commit -m "Update menu redirect to new location"
git pushThat's it! Within 1-2 minutes:
- GitHub Actions rebuilds the site
/menunow redirects to the new URL- Your existing QR codes work with the new destination
- No QR code regeneration needed!
Edit _extensions/redirect/redirect.html to change:
- Loading message
- Spinner animation
- Colors and styling
- Fallback link text
Edit generate_qr_codes.py to adjust:
- Error correction level
- Box size
- Border width
- Colors (fill/background)
Example:
qr = qrcode.QRCode(
version=1,
error_correction=qrcode.constants.ERROR_CORRECT_H, # Higher correction
box_size=15, # Larger boxes
border=2, # Smaller border
)Add tracking to _extensions/redirect/redirect.html:
<script>
// Log redirect event
console.log('Redirecting from: $slug$');
console.log('Redirecting to: $target_url$');
// Add your analytics code here
// e.g., Google Analytics, Plausible, etc.
</script>- Restaurant Menus: Update menu links seasonally without reprinting QR codes
- Event Registration: Change registration forms for recurring events
- Product Links: Update product pages without changing packaging
- Contact Information: Update contact forms or vCards
- Promotional Campaigns: Rotate promotional landing pages
- Documentation: Keep printed materials pointing to latest docs
Check workflow permissions:
- Settings β Actions β General
- Workflow permissions β Read and write permissions
Check Pages settings:
- Settings β Pages
- Source should be
gh-pagesbranch
Verify file structure:
- Markdown files must be in
_redirects/folder - Must have
.qmdextension - Must include
slugandtarget_urlin frontmatter
Check build logs:
- Go to Actions tab
- Click latest workflow run
- Check for errors in build step
Verify Python environment:
# Activate virtual environment
source venv/bin/activate
# Reinstall dependencies
pip install -r requirements.txtCheck file paths:
- Script must be run from project root
_redirects/folder must exist
The workflow (.github/workflows/publish.yml) automatically:
- Triggers on every push to
mainbranch - Checks out your repository
- Sets up Quarto
- Renders the site (converts
.qmdto HTML) - Uploads the
_sitefolder as an artifact - Deploys to GitHub Pages
View workflow runs: Repository β Actions tab
- All redirects are public (GitHub Pages is public)
- Don't store sensitive URLs in redirect targets
- Consider using URL shorteners for additional privacy
- QR codes are permanentβchoose slugs carefully
Contributions welcome! Please:
- Fork the repository
- Create a feature branch
- Make your changes
- Submit a pull request
This project is licensed under the MIT License - see the LICENSE file for details.
- Choose meaningful slugs: Use short, memorable slugs like
menu,contact,promo - Test before printing: Always test redirects before printing QR codes
- Keep a backup: Document your slug β purpose mapping
- Use descriptive commits: Makes tracking changes easier
- Monitor analytics: Track which QR codes get the most scans
- Set up notifications: Get alerts when Actions fail
You now have a fully functional, zero-cost dynamic QR code system!
Next steps:
- Generate your QR codes
- Print and distribute them
- Update redirect targets anytime by editing Markdown files
- Watch GitHub Actions automatically deploy your changes
Built with β€οΈ using Quarto, Python, and GitHub Pages