feat: add marketing landing pages and tools for dynamic QR codes and analytics

This commit is contained in:
Timo Knuth
2026-04-07 14:50:16 +02:00
parent 8408159a96
commit a6fd2ed61f
14 changed files with 1360 additions and 92 deletions

View File

@@ -0,0 +1,213 @@
'use client';
import React, { useState, useRef } from 'react';
import { QRCodeSVG } from 'qrcode.react';
import { toPng } from 'html-to-image';
import { Star, Download, AlertCircle } from 'lucide-react';
import { Button } from '@/components/ui/Button';
import { Input } from '@/components/ui/Input';
const QR_COLORS = [
{ name: 'Google Blue', value: '#1A73E8' },
{ name: 'Classic Black', value: '#000000' },
{ name: 'Indigo', value: '#4F46E5' },
{ name: 'Emerald', value: '#10B981' },
{ name: 'Rose', value: '#F43F5E' },
{ name: 'Violet', value: '#7C3AED' },
];
const FRAME_OPTIONS = [
{ id: 'none', label: 'No Frame' },
{ id: 'review', label: 'Leave a Review' },
{ id: 'scanme', label: 'Scan Me' },
{ id: 'feedback', label: 'Share Feedback' },
];
function isValidGoogleReviewLink(url: string): boolean {
try {
const parsed = new URL(url);
return (
parsed.hostname.includes('google.com') ||
parsed.hostname.includes('g.page') ||
parsed.hostname.includes('maps.app.goo.gl')
);
} catch {
return false;
}
}
export default function GoogleReviewGenerator() {
const [reviewUrl, setReviewUrl] = useState('');
const [qrColor, setQrColor] = useState('#1A73E8');
const [frameType, setFrameType] = useState('review');
const [error, setError] = useState('');
const qrRef = useRef<HTMLDivElement>(null);
const handleUrlChange = (value: string) => {
setReviewUrl(value);
if (value && !isValidGoogleReviewLink(value)) {
setError('Please enter a valid Google Review link (google.com, g.page, or maps.app.goo.gl)');
} else {
setError('');
}
};
const handleDownload = async (format: 'png' | 'svg') => {
if (!qrRef.current) return;
try {
if (format === 'png') {
const dataUrl = await toPng(qrRef.current, { cacheBust: true, pixelRatio: 3 });
const link = document.createElement('a');
link.download = 'google-review-qr-code.png';
link.href = dataUrl;
link.click();
} else {
const svgData = qrRef.current.querySelector('svg')?.outerHTML;
if (svgData) {
const blob = new Blob([svgData], { type: 'image/svg+xml;charset=utf-8' });
const url = URL.createObjectURL(blob);
const link = document.createElement('a');
link.href = url;
link.download = 'google-review-qr-code.svg';
link.click();
}
}
} catch (err) {
console.error('Download failed', err);
}
};
const frameLabel = FRAME_OPTIONS.find(f => f.id === frameType && f.id !== 'none')?.label ?? null;
const isReady = reviewUrl && !error && isValidGoogleReviewLink(reviewUrl);
return (
<div className="w-full max-w-5xl mx-auto px-4 md:px-6">
<div className="bg-white rounded-3xl shadow-2xl shadow-slate-900/10 overflow-hidden border border-slate-100">
<div className="grid lg:grid-cols-2">
{/* LEFT: Input */}
<div className="p-6 md:p-8 lg:p-10 space-y-8 border-r border-slate-100">
<div className="space-y-4">
<h2 className="text-lg font-bold text-slate-900 flex items-center gap-2">
<Star className="w-5 h-5 text-yellow-500" />
Your Google Review Link
</h2>
<div>
<Input
type="url"
placeholder="https://g.page/r/YOUR_ID/review"
value={reviewUrl}
onChange={(e) => handleUrlChange(e.target.value)}
className="w-full font-mono text-sm"
/>
{error && (
<div className="mt-2 flex items-center gap-2 text-sm text-red-600">
<AlertCircle className="w-4 h-4 shrink-0" />
{error}
</div>
)}
{!reviewUrl && (
<p className="mt-2 text-xs text-slate-500">
Go to Google Maps find your business Share Copy link
</p>
)}
</div>
</div>
{/* Color Picker */}
<div className="space-y-3">
<h3 className="text-sm font-semibold text-slate-700">QR Color</h3>
<div className="flex flex-wrap gap-2">
{QR_COLORS.map((color) => (
<button
key={color.value}
onClick={() => setQrColor(color.value)}
className={`w-8 h-8 rounded-full border-2 transition-all ${
qrColor === color.value
? 'border-slate-900 scale-110'
: 'border-transparent hover:border-slate-300'
}`}
style={{ backgroundColor: color.value }}
title={color.name}
/>
))}
</div>
</div>
{/* Frame */}
<div className="space-y-3">
<h3 className="text-sm font-semibold text-slate-700">Frame Label</h3>
<div className="grid grid-cols-2 gap-2">
{FRAME_OPTIONS.map((frame) => (
<button
key={frame.id}
onClick={() => setFrameType(frame.id)}
className={`px-3 py-2 rounded-xl text-sm font-medium border transition-all ${
frameType === frame.id
? 'border-blue-600 bg-blue-50 text-blue-700'
: 'border-slate-200 text-slate-600 hover:border-slate-300'
}`}
>
{frame.label}
</button>
))}
</div>
</div>
{/* Download Buttons */}
<div className="space-y-3">
<Button
onClick={() => handleDownload('png')}
disabled={!isReady}
className="w-full flex items-center justify-center gap-2"
>
<Download className="w-4 h-4" />
Download PNG
</Button>
<button
onClick={() => handleDownload('svg')}
disabled={!isReady}
className="w-full px-4 py-2.5 rounded-xl border border-slate-200 text-slate-700 text-sm font-medium hover:border-slate-300 hover:bg-slate-50 transition-all disabled:opacity-40 disabled:cursor-not-allowed flex items-center justify-center gap-2"
>
<Download className="w-4 h-4" />
Download SVG
</button>
</div>
</div>
{/* RIGHT: Preview */}
<div className="p-6 md:p-8 lg:p-10 flex flex-col items-center justify-center bg-slate-50">
<h3 className="text-sm font-semibold text-slate-500 uppercase tracking-wider mb-6">Preview</h3>
<div ref={qrRef} className="flex flex-col items-center bg-white p-6 rounded-2xl shadow-sm border border-slate-100">
<QRCodeSVG
value={isReady ? reviewUrl : 'https://www.qrmaster.net/tools/google-review-qr-code'}
size={200}
fgColor={qrColor}
level="Q"
includeMargin={true}
/>
{frameLabel && (
<div
className="mt-3 px-4 py-1.5 rounded-full text-sm font-semibold text-white"
style={{ backgroundColor: qrColor }}
>
{frameLabel}
</div>
)}
</div>
{!isReady && (
<p className="mt-4 text-xs text-slate-400 text-center max-w-[200px]">
Enter your Google Review link to generate your QR code
</p>
)}
</div>
</div>
</div>
</div>
);
}

View File

@@ -0,0 +1,366 @@
import React from 'react';
import type { Metadata } from 'next';
import GoogleReviewGenerator from './GoogleReviewGenerator';
import { Star, MapPin, Search, Share2 } from 'lucide-react';
import { QRCodeSVG } from 'qrcode.react';
import { ToolBreadcrumb } from '@/components/seo/BreadcrumbSchema';
import { RelatedTools } from '@/components/marketing/RelatedTools';
import { GrowthLinksSection } from '@/components/marketing/GrowthLinksSection';
import { generateSoftwareAppSchema } from '@/lib/schema-utils';
export const metadata: Metadata = {
title: {
absolute: 'Google Review QR Code Generator — Free | QR Master',
},
description: 'Create a QR code for your Google Reviews in seconds. Customers scan once and land directly on your review form. Free, no signup required.',
keywords: ['qr code for google reviews', 'qr code generator for google reviews', 'google review qr code', 'google maps review qr code', 'get more google reviews'],
alternates: {
canonical: 'https://www.qrmaster.net/tools/google-review-qr-code',
},
openGraph: {
title: 'Google Review QR Code Generator — Free | QR Master',
description: 'Create a QR code that takes customers directly to your Google review form. More reviews, less friction.',
type: 'website',
url: 'https://www.qrmaster.net/tools/google-review-qr-code',
},
twitter: {
card: 'summary_large_image',
title: 'Google Review QR Code Generator — Free',
description: 'Create a QR code that takes customers directly to your Google review form.',
},
robots: {
index: true,
follow: true,
},
};
const jsonLd = {
'@context': 'https://schema.org',
'@graph': [
generateSoftwareAppSchema(
'Google Review QR Code Generator',
'Generate a QR code that links directly to your Google review form. Customers scan once and can leave a review immediately.',
'/og-image.png'
),
{
'@type': 'HowTo',
name: 'How to Create a Google Review QR Code',
description: 'Generate a QR code that sends customers directly to your Google review form.',
step: [
{
'@type': 'HowToStep',
position: 1,
name: 'Find your Google Review link',
text: 'Open Google Maps, search for your business, click Share → Copy link. Or use Google Business Profile → Get more reviews.',
},
{
'@type': 'HowToStep',
position: 2,
name: 'Paste the link into the generator',
text: 'Paste your Google review URL into the field above. The generator accepts g.page, google.com, and maps.app.goo.gl links.',
},
{
'@type': 'HowToStep',
position: 3,
name: 'Customize and download',
text: 'Choose a color and frame label (e.g. "Leave a Review"), then download as PNG or SVG.',
},
{
'@type': 'HowToStep',
position: 4,
name: 'Display the QR code',
text: 'Print the code on receipts, table cards, packaging, or your window. Customers scan once to review.',
},
],
totalTime: 'PT60S',
},
{
'@type': 'FAQPage',
mainEntity: [
{
'@type': 'Question',
name: 'How do I find my Google Review link?',
acceptedAnswer: {
'@type': 'Answer',
text: 'Open Google Maps → search for your business → click Share → Copy link. Alternatively, go to your Google Business Profile dashboard → click "Get more reviews" — this gives you a direct review shortlink.',
},
},
{
'@type': 'Question',
name: 'Does this Google Review QR code expire?',
acceptedAnswer: {
'@type': 'Answer',
text: 'No. This is a static QR code that directly encodes your Google review URL. It will work as long as your Google Business Profile is active.',
},
},
{
'@type': 'Question',
name: 'Can I track how many people scanned the QR code?',
acceptedAnswer: {
'@type': 'Answer',
text: 'Not with a static QR code. If you need scan analytics (device, location, time), create a dynamic QR code with tracking through QR Master.',
},
},
{
'@type': 'Question',
name: 'What happens when a customer scans the QR code?',
acceptedAnswer: {
'@type': 'Answer',
text: 'They are taken directly to your Google review form. If they are logged into a Google account on their phone, they can leave a review immediately with no extra steps.',
},
},
{
'@type': 'Question',
name: 'Where should I display the Google Review QR code?',
acceptedAnswer: {
'@type': 'Answer',
text: 'Best placements: receipts, table tent cards (restaurants), checkout counters, packaging inserts, and your shop window. The moment after a positive experience is the best time to ask for a review.',
},
},
],
},
{
'@type': 'BreadcrumbList',
itemListElement: [
{ '@type': 'ListItem', position: 1, name: 'Home', item: 'https://www.qrmaster.net' },
{ '@type': 'ListItem', position: 2, name: 'QR Code Tools', item: 'https://www.qrmaster.net/tools' },
{ '@type': 'ListItem', position: 3, name: 'Google Review QR Code Generator', item: 'https://www.qrmaster.net/tools/google-review-qr-code' },
],
},
],
};
export default function GoogleReviewQRCodePage() {
return (
<>
<script
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: JSON.stringify(jsonLd) }}
/>
<ToolBreadcrumb toolName="Google Review QR Code Generator" toolSlug="google-review-qr-code" />
<div className="min-h-screen" style={{ backgroundColor: '#EBEBDF' }}>
{/* HERO */}
<section className="relative pt-20 pb-20 lg:pt-32 lg:pb-32 px-4 sm:px-6 lg:px-8 overflow-hidden bg-[#1A1265]">
<div className="max-w-7xl mx-auto grid lg:grid-cols-2 gap-12 items-center relative z-10">
<div className="text-center lg:text-left">
<div className="inline-flex items-center gap-2 px-3 py-1 rounded-full bg-white/10 text-white/90 text-sm font-medium mb-6 border border-white/10">
<span className="flex h-2 w-2 relative">
<span className="animate-ping absolute inline-flex h-full w-full rounded-full bg-yellow-400 opacity-75"></span>
<span className="relative inline-flex rounded-full h-2 w-2 bg-yellow-400"></span>
</span>
Free Tool No Signup Required
</div>
<h1 className="text-4xl md:text-5xl lg:text-6xl font-extrabold text-white tracking-tight leading-tight mb-6">
Google Review QR Code <br className="hidden lg:block" />
<span className="text-transparent bg-clip-text bg-gradient-to-r from-yellow-400 to-orange-400">Generator Free</span>
</h1>
<p className="text-lg md:text-xl text-indigo-100 max-w-2xl mx-auto lg:mx-0 mb-8 leading-relaxed">
Customers scan once and land directly on your Google review form.
<strong className="text-white block sm:inline mt-2 sm:mt-0"> More reviews, less friction.</strong>
</p>
<div className="flex flex-wrap justify-center lg:justify-start gap-4 text-sm font-medium text-white/80">
<div className="flex items-center gap-2 bg-white/5 px-4 py-2.5 rounded-xl border border-white/5">
<Star className="w-4 h-4 text-yellow-400" />
Direct to Review Form
</div>
<div className="flex items-center gap-2 bg-white/5 px-4 py-2.5 rounded-xl border border-white/5">
<MapPin className="w-4 h-4 text-emerald-400" />
Works for Any Business
</div>
</div>
</div>
{/* Hero QR Visual */}
<div className="hidden lg:flex relative items-center justify-center min-h-[400px]">
<div className="absolute w-[500px] h-[500px] bg-yellow-500/20 rounded-full blur-[100px] -top-20 -right-20 animate-pulse" />
<div className="relative w-80 h-96 bg-white/5 backdrop-blur-xl border border-white/20 rounded-3xl shadow-2xl flex flex-col items-center justify-center p-8 transform -rotate-3 hover:rotate-0 transition-all duration-700 group">
<div className="absolute inset-0 bg-gradient-to-br from-white/10 to-transparent rounded-3xl" />
<div className="w-48 h-48 bg-white rounded-xl p-2 shadow-inner mb-6 relative overflow-hidden flex items-center justify-center">
<QRCodeSVG value="https://www.qrmaster.net/tools/google-review-qr-code" size={170} fgColor="#1A73E8" level="Q" />
</div>
<div className="w-full bg-white/10 rounded-xl p-4 backdrop-blur-sm border border-white/10">
<div className="flex items-center gap-3">
<div className="w-8 h-8 rounded-full bg-yellow-500/20 flex items-center justify-center">
<Star className="w-4 h-4 text-yellow-300" />
</div>
<div className="space-y-1 w-full">
<div className="h-1.5 w-3/4 bg-white/30 rounded-full" />
<div className="h-1.5 w-1/2 bg-white/20 rounded-full" />
</div>
</div>
</div>
</div>
</div>
</div>
</section>
{/* GENERATOR */}
<section className="py-12 px-4 sm:px-6 lg:px-8 -mt-8">
<GoogleReviewGenerator />
</section>
{/* HOW TO FIND YOUR REVIEW LINK */}
<section className="py-16 px-4 sm:px-6 lg:px-8 bg-white">
<div className="max-w-4xl mx-auto">
<h2 className="text-3xl font-bold text-slate-900 text-center mb-4">
How to Find Your Google Review Link
</h2>
<p className="text-slate-600 text-center mb-12 max-w-2xl mx-auto">
You need your Google Business review URL before creating the QR code. Here are two ways to get it.
</p>
<div className="grid md:grid-cols-2 gap-8">
<article className="p-6 bg-slate-50 rounded-2xl border border-slate-100">
<div className="w-12 h-12 rounded-xl bg-blue-100 flex items-center justify-center mb-4">
<Search className="w-6 h-6 text-blue-600" />
</div>
<h3 className="font-bold text-slate-900 mb-3">Method 1: Google Maps</h3>
<ol className="space-y-2 text-sm text-slate-600 list-none">
<li><span className="font-semibold text-slate-800">1.</span> Open Google Maps</li>
<li><span className="font-semibold text-slate-800">2.</span> Search for your business name</li>
<li><span className="font-semibold text-slate-800">3.</span> Click the <strong>Share</strong> button</li>
<li><span className="font-semibold text-slate-800">4.</span> Copy the short link (starts with <code className="bg-white px-1 rounded text-xs">maps.app.goo.gl</code> or <code className="bg-white px-1 rounded text-xs">g.page</code>)</li>
<li><span className="font-semibold text-slate-800">5.</span> Paste into the generator above</li>
</ol>
</article>
<article className="p-6 bg-slate-50 rounded-2xl border border-slate-100">
<div className="w-12 h-12 rounded-xl bg-yellow-100 flex items-center justify-center mb-4">
<Share2 className="w-6 h-6 text-yellow-600" />
</div>
<h3 className="font-bold text-slate-900 mb-3">Method 2: Google Business Profile</h3>
<ol className="space-y-2 text-sm text-slate-600 list-none">
<li><span className="font-semibold text-slate-800">1.</span> Sign in to <strong>business.google.com</strong></li>
<li><span className="font-semibold text-slate-800">2.</span> Select your business location</li>
<li><span className="font-semibold text-slate-800">3.</span> Click <strong>"Get more reviews"</strong></li>
<li><span className="font-semibold text-slate-800">4.</span> Copy the review shortlink provided</li>
<li><span className="font-semibold text-slate-800">5.</span> Paste into the generator above</li>
</ol>
</article>
</div>
</div>
</section>
{/* USE CASES */}
<section className="py-16 px-4 sm:px-6 lg:px-8" style={{ backgroundColor: '#EBEBDF' }}>
<div className="max-w-5xl mx-auto">
<h2 className="text-3xl font-bold text-slate-900 text-center mb-4">
Who Uses Google Review QR Codes?
</h2>
<p className="text-slate-600 text-center mb-12">
Any business where the moment of satisfaction happens in person.
</p>
<div className="grid sm:grid-cols-2 lg:grid-cols-4 gap-6">
{[
{ icon: '🍽️', title: 'Restaurants & Cafés', text: 'Print on receipts or table cards. Ask after the meal when the experience is fresh.' },
{ icon: '🏨', title: 'Hotels & Guesthouses', text: 'Place on checkout envelopes or in-room cards. Capture reviews at checkout.' },
{ icon: '🏥', title: 'Clinics & Salons', text: 'Display at reception. Patients and clients who had a great experience can review in seconds.' },
{ icon: '🛍️', title: 'Retail & Shops', text: 'Include in packaging or display at checkout. Turn happy shoppers into reviewers.' },
].map((item) => (
<article key={item.title} className="p-6 bg-white rounded-2xl border border-slate-100 shadow-sm">
<div className="text-3xl mb-3">{item.icon}</div>
<h3 className="font-bold text-slate-900 mb-2">{item.title}</h3>
<p className="text-sm text-slate-600 leading-relaxed">{item.text}</p>
</article>
))}
</div>
</div>
</section>
<GrowthLinksSection
eyebrow="Level up your local marketing"
title="More QR workflows for local businesses"
description="Review QR codes work best alongside dynamic destination management and scan tracking."
links={[
{
href: '/qr-code-for/restaurants',
title: 'QR Codes for Restaurants',
description: 'Menu, ordering, and review QR workflows built for food service businesses.',
ctaLabel: 'Restaurant QR workflows',
},
{
href: '/qr-code-for/hotels',
title: 'QR Codes for Hotels',
description: 'Check-in, room service, and review QR setups for hospitality.',
ctaLabel: 'Hotel QR workflows',
},
{
href: '/dynamic-qr-code-generator',
title: 'Dynamic QR Code Generator',
description: 'Update your review link or redirect to a different page anytime — no reprint needed.',
ctaLabel: 'Create dynamic QR code',
},
{
href: '/qr-code-tracking',
title: 'QR Code Tracking',
description: 'See exactly how many people scanned your review QR code and from which location.',
ctaLabel: 'Track QR code scans',
},
]}
pageType="commercial"
cluster="google-review-qr"
/>
<RelatedTools />
{/* FAQ */}
<section className="py-16 px-4 sm:px-6 lg:px-8" style={{ backgroundColor: '#EBEBDF' }}>
<div className="max-w-3xl mx-auto">
<h2 className="text-3xl font-bold text-slate-900 text-center mb-4">
Frequently Asked Questions
</h2>
<p className="text-slate-600 text-center mb-10">
Common questions about Google Review QR codes.
</p>
<div className="space-y-4">
{[
{
question: 'How do I find my Google Review link?',
answer: 'Open Google Maps → search your business → click Share → Copy link. Or go to Google Business Profile → "Get more reviews" for a direct shortlink.',
},
{
question: 'Does the Google Review QR code expire?',
answer: 'No. This is a static QR code that encodes your Google review URL directly. It works indefinitely as long as your Google Business Profile is active.',
},
{
question: 'Can I track how many people scanned it?',
answer: 'Not with a static QR code. For scan analytics (device, location, time), create a dynamic QR code with tracking through QR Master.',
},
{
question: 'What happens when a customer scans the QR code?',
answer: 'They are taken directly to your Google review form. If they are logged into a Google account, they can leave a star rating and review immediately.',
},
{
question: 'Where should I put the Google Review QR code?',
answer: 'Best placements: receipts, table cards, checkout counters, packaging inserts, and your shop window. Ask for reviews right after the positive experience.',
},
].map((item) => (
<details key={item.question} className="group bg-white rounded-xl shadow-sm border border-slate-200 overflow-hidden">
<summary className="flex items-center justify-between p-5 cursor-pointer list-none text-slate-900 font-semibold hover:bg-slate-50 transition-colors">
{item.question}
<span className="transition group-open:rotate-180 text-slate-400">
<svg fill="none" height="20" stroke="currentColor" strokeLinecap="round" strokeLinejoin="round" strokeWidth="2" viewBox="0 0 24 24" width="20">
<path d="M6 9l6 6 6-6" />
</svg>
</span>
</summary>
<div className="text-slate-600 px-5 pb-5 pt-0 leading-relaxed text-sm">
{item.answer}
</div>
</details>
))}
</div>
</div>
</section>
</div>
</>
);
}

View File

@@ -5,6 +5,7 @@ import { User, Shield, Zap, Smartphone, Contact, Share2, Check, UserPlus } from
import { QRCodeSVG } from 'qrcode.react';
import { ToolBreadcrumb } from '@/components/seo/BreadcrumbSchema';
import { RelatedTools } from '@/components/marketing/RelatedTools';
import { GrowthLinksSection } from '@/components/marketing/GrowthLinksSection';
import { generateSoftwareAppSchema, generateFaqSchema } from '@/lib/schema-utils';
// SEO Optimized Metadata
@@ -238,6 +239,29 @@ export default function VCardQRCodePage() {
</div>
</section>
{/* GROWTH LINKS */}
<GrowthLinksSection
eyebrow="Level up your QR strategy"
title="More ways to use QR codes for your brand"
description="A vCard QR code is a great start. Add custom design, tracking, and dynamic destinations to get the most out of every print."
links={[
{
href: '/custom-qr-code-generator',
title: 'Custom QR Code Generator',
description: 'Add your logo, brand colors, and a custom frame to your QR codes.',
ctaLabel: 'Custom QR with logo',
},
{
href: '/dynamic-qr-code-generator',
title: 'Dynamic QR Code Generator',
description: 'Update your contact destination after printing. No new QR code needed.',
ctaLabel: 'Dynamic QR with tracking',
},
]}
pageType="commercial"
cluster="vcard-qr"
/>
{/* RELATED TOOLS */}
<RelatedTools />