
Qr Code Generator
- 229 installs
- 84 repo stars
- Updated April 8, 2026
- dkyazzentwatwa/chatgpt-skills
Produce branded QR codes for URLs, Wi-Fi, vCards, or payment payloads inside marketing pages, tickets, and onboarding flows.
About
Helps Claude Code generate correct, scannable QR codes with appropriate error correction, sizing, and export formats for web and mobile surfaces, covering static marketing codes and dynamic deep links tied to campaigns or in-app actions.
- Payload types and size limits
- SVG/PNG export options
- Error correction levels
- Brand color and logo safe zones
- Batch or dynamic code patterns
Qr Code Generator by the numbers
- 229 all-time installs (skills.sh)
- Ranked #818 of 2,244 Frontend Development skills by installs in the Skillselion catalog
- Data as of Aug 4, 2026 (Skillselion catalog sync)
npx skills add https://github.com/dkyazzentwatwa/chatgpt-skills --skill qr-code-generatorAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 229 |
|---|---|
| repo stars | ★ 84 |
| Last updated | April 8, 2026 |
| Repository | dkyazzentwatwa/chatgpt-skills ↗ |
What it does
Produce branded QR codes for URLs, Wi-Fi, vCards, or payment payloads inside marketing pages, tickets, and onboarding flows.
Files
QR Code Generator
Create QR assets that are safe to print, easy to scan, and explicit about the encoded destination.
Workflow
1. Validate the target URL and prefer HTTPS. 2. Add UTM parameters only when the campaign needs them. 3. Generate single codes with scripts/generate_qr.py or batches with scripts/batch_generate.py. 4. Prefer SVG and higher error correction for print uses.
Guardrails
- Do not generate QR codes for suspicious or deceptive destinations.
- Return the final encoded URL alongside the output files.
- Explain when PNG is fine and when SVG is the better choice.
display_name: 'QR Code Generator'
short_description: 'Create QR codes with safe URLs and print-friendly exports.'
default_prompt: 'Help me generate a QR code for this destination.'
Print notes for QR codes
- Prefer SVG for print (crisp at any size).
- Use error correction H for:
- stickers
- glossy surfaces
- codes that might get scratched
- when you add a logo (not supported in this pack yet)
- Minimum practical sizes:
- phone screen / web: 256–512px PNG
- print: at least ~1 inch (2.5cm) for simple URLs; larger for distance scanning
- Keep enough “quiet zone” (border). Border 4 is a good default.
- Always test scan on 2–3 different phones before shipping.
Prompt snippets
Single QR (PNG + SVG)
Use the qr-code-generator skill. Generate a QR for: URL: https://example.com Caption label: Scan to visit Show URL under code: no Formats: png, svg Error correction: H
QR with UTM tracking
Use the qr-code-generator skill. URL: https://example.com/pricing UTM:
- source: linkedin
- medium: qr
- campaign: jan_2026_launch
Caption: Scan for pricing Formats: svg
Batch
Use the qr-code-generator skill. Here’s a CSV with id,url,label. Generate SVGs for print with error correction H.
{
"utm_source": "newsletter",
"utm_medium": "qr",
"utm_campaign": "winter_launch",
"utm_content": "",
"utm_term": ""
}Safety + quality checklist
Before you ship a QR:
- Verify the destination loads fast on mobile.
- Make sure the QR encodes the final URL (with UTM if used).
- Test scanning in:
- bright light
- dim light
- from the expected distance
- If it’s a payment/login link, consider using a landing page instead.
Avoid:
- Shorteners you don’t control (harder to trust)
- URLs with spaces or weird characters (always URL-encode)
#!/usr/bin/env python3
"""
Batch-generate QR codes from a CSV with columns:
id,url,label
Example:
python batch_generate.py --csv inputs.csv --outdir /mnt/data/qrs --format svg --error H
Requires: qrcode, pillow (for PNG)
"""
from __future__ import annotations
import argparse
import csv
import os
import subprocess
import sys
from pathlib import Path
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--csv", required=True, help="Path to CSV file with id,url,label columns.")
ap.add_argument("--outdir", required=True, help="Output directory.")
ap.add_argument("--format", default="svg", choices=["png","svg","both"])
ap.add_argument("--error", default="H", choices=["L","M","Q","H"])
ap.add_argument("--show-url", action="store_true")
args = ap.parse_args()
Path(args.outdir).mkdir(parents=True, exist_ok=True)
script = Path(__file__).with_name("generate_qr.py")
with open(args.csv, newline="", encoding="utf-8") as f:
reader = csv.DictReader(f)
for row in reader:
_id = (row.get("id") or "").strip()
url = (row.get("url") or "").strip()
label = (row.get("label") or "").strip()
if not _id or not url:
continue
png = os.path.join(args.outdir, f"{_id}.png") if args.format in ("png","both") else ""
svg = os.path.join(args.outdir, f"{_id}.svg") if args.format in ("svg","both") else ""
cmd = [sys.executable, str(script), "--url", url, "--error", args.error]
if png: cmd += ["--png", png]
if svg: cmd += ["--svg", svg]
if label: cmd += ["--caption-label", label]
if args.show_url: cmd += ["--show-url"]
subprocess.check_call(cmd)
if __name__ == "__main__":
main()
#!/usr/bin/env python3
"""
Generate a QR code that encodes a URL. Export PNG and/or SVG.
Optionally add a caption (label and/or URL) under the QR.
Examples:
python generate_qr.py --url "https://example.com" --png "/mnt/data/qr.png" --svg "/mnt/data/qr.svg"
python generate_qr.py --url "https://example.com" --png "/mnt/data/qr.png" --caption-label "Scan me" --show-url
Notes:
- Requires: qrcode, pillow (PIL)
"""
from __future__ import annotations
import argparse
import sys
from urllib.parse import urlparse, urlencode, parse_qsl, urlunparse
import qrcode
from qrcode.constants import ERROR_CORRECT_L, ERROR_CORRECT_M, ERROR_CORRECT_Q, ERROR_CORRECT_H
def validate_url(u: str) -> str:
u = u.strip()
parsed = urlparse(u)
if parsed.scheme not in ("http", "https"):
raise ValueError("URL must start with http:// or https://")
if not parsed.netloc:
raise ValueError("URL must include a domain (netloc).")
return u
def add_utm(url: str, utm: dict[str, str]) -> str:
parsed = urlparse(url)
query = dict(parse_qsl(parsed.query, keep_blank_values=True))
# Only set if provided and non-empty
for k, v in utm.items():
if v:
query[f"utm_{k}"] = v if k.startswith(("source","medium","campaign","content","term")) else v
new_query = urlencode(query, doseq=True)
return urlunparse(parsed._replace(query=new_query))
def err_level(level: str):
level = level.upper()
return {
"L": ERROR_CORRECT_L,
"M": ERROR_CORRECT_M,
"Q": ERROR_CORRECT_Q,
"H": ERROR_CORRECT_H,
}[level]
def make_qr(data: str, error: str, box_size: int, border: int):
qr = qrcode.QRCode(
version=None,
error_correction=err_level(error),
box_size=box_size,
border=border,
)
qr.add_data(data)
qr.make(fit=True)
return qr
def export_png(qr, path: str, caption_label: str | None, show_url: bool, url: str | None):
from PIL import Image, ImageDraw, ImageFont
img = qr.make_image(fill_color="black", back_color="white").convert("RGB")
if not (caption_label or (show_url and url)):
img.save(path)
return
font = ImageFont.load_default()
lines = []
if caption_label:
lines.append(caption_label.strip())
if show_url and url:
lines.append(url.strip())
# Measure text
draw = ImageDraw.Draw(img)
padding = 16
line_h = 14 # approximate for default font
text_h = len(lines) * (line_h + 6)
new_w = img.width
new_h = img.height + padding + text_h + padding
out = Image.new("RGB", (new_w, new_h), "white")
out.paste(img, (0, 0))
draw2 = ImageDraw.Draw(out)
y = img.height + padding
for line in lines:
bbox = draw2.textbbox((0, 0), line, font=font)
w = bbox[2] - bbox[0]
x = max(0, (new_w - w) // 2)
draw2.text((x, y), line, fill="black", font=font)
y += line_h + 6
out.save(path)
def export_svg(qr, path: str, caption_label: str | None, show_url: bool, url: str | None):
from qrcode.image.svg import SvgImage
img = qr.make_image(image_factory=SvgImage)
svg = img.to_string().decode("utf-8")
if not (caption_label or (show_url and url)):
PathWrite(path, svg)
return
# Very simple SVG text injection.
# We append text at the bottom with a viewBox expansion.
# Works for most viewers; keep it minimal.
caption_lines = []
if caption_label:
caption_lines.append(caption_label.strip())
if show_url and url:
caption_lines.append(url.strip())
# Extract viewBox
import re
m = re.search(r'viewBox="0 0 (\d+) (\d+)"', svg)
if not m:
PathWrite(path, svg)
return
w = int(m.group(1))
h = int(m.group(2))
extra = 70 + 20 * (len(caption_lines) - 1)
new_h = h + extra
svg2 = re.sub(r'viewBox="0 0 \d+ \d+"', f'viewBox="0 0 {w} {new_h}"', svg, count=1)
# Add text before closing </svg>
text_y = h + 35
text_elems = []
for line in caption_lines:
text_elems.append(
f'<text x="{w/2:.1f}" y="{text_y}" text-anchor="middle" font-family="Arial, sans-serif" font-size="18" fill="#000">{EscapeXML(line)}</text>'
)
text_y += 24
svg2 = svg2.replace("</svg>", "\n" + "\n".join(text_elems) + "\n</svg>")
PathWrite(path, svg2)
def EscapeXML(s: str) -> str:
return (s.replace("&", "&")
.replace("<", "<")
.replace(">", ">")
.replace('"', """)
.replace("'", "'"))
def PathWrite(path: str, content: str):
from pathlib import Path
Path(path).parent.mkdir(parents=True, exist_ok=True)
Path(path).write_text(content, encoding="utf-8")
def main():
ap = argparse.ArgumentParser()
ap.add_argument("--url", required=True, help="Destination URL to encode.")
ap.add_argument("--png", default="", help="Output PNG path (optional).")
ap.add_argument("--svg", default="", help="Output SVG path (optional).")
ap.add_argument("--error", default="M", choices=["L","M","Q","H"], help="Error correction level.")
ap.add_argument("--box-size", type=int, default=10, help="QR pixel size per module (PNG).")
ap.add_argument("--border", type=int, default=4, help="Quiet zone border (modules).")
ap.add_argument("--caption-label", default="", help="Optional caption label (e.g., 'Scan to...').")
ap.add_argument("--show-url", action="store_true", help="Include the URL as a caption line.")
ap.add_argument("--utm-source", default="", dest="utm_source")
ap.add_argument("--utm-medium", default="", dest="utm_medium")
ap.add_argument("--utm-campaign", default="", dest="utm_campaign")
ap.add_argument("--utm-content", default="", dest="utm_content")
ap.add_argument("--utm-term", default="", dest="utm_term")
args = ap.parse_args()
url = validate_url(args.url)
utm = {
"source": args.utm_source,
"medium": args.utm_medium,
"campaign": args.utm_campaign,
"content": args.utm_content,
"term": args.utm_term,
}
final_url = add_utm(url, utm) if any(utm.values()) else url
qr = make_qr(final_url, args.error, args.box_size, args.border)
caption_label = args.caption_label.strip() or None
if not args.png and not args.svg:
# Default output
args.png = "qr.png"
if args.png:
export_png(qr, args.png, caption_label, args.show_url, final_url)
if args.svg:
export_svg(qr, args.svg, caption_label, args.show_url, final_url)
print(final_url)
if __name__ == "__main__":
try:
main()
except Exception as e:
print(f"ERROR: {e}", file=sys.stderr)
sys.exit(1)
qrcode>=7.3.1
pillow>=9.0.0