neuer versuch

This commit is contained in:
Timo Knuth 2026-01-14 14:02:48 +01:00
parent 1747922b29
commit f68b7a331c
53 changed files with 3560 additions and 4397 deletions

14
firecrawl-config.json Normal file
View File

@ -0,0 +1,14 @@
{
"mcpServers": {
"firecrawl": {
"command": "npx",
"args": [
"-y",
"firecrawl-mcp"
],
"env": {
"FIRECRAWL_API_KEY": "fc-268826f038ad4bf0a38c48690ba9c1fa"
}
}
}
}

View File

@ -1,42 +0,0 @@
/** @type {import('next-sitemap').IConfig} */
module.exports = {
siteUrl: 'https://www.qrmaster.net',
generateRobotsTxt: true,
robotsTxtOptions: {
policies: [
{
userAgent: '*',
allow: '/',
},
],
},
transform: async (config, path) => {
// Custom priority and changefreq based on path
let priority = 0.7;
let changefreq = 'weekly';
if (path === '/') {
priority = 0.9;
changefreq = 'daily';
} else if (path === '/blog') {
priority = 0.7;
changefreq = 'daily';
} else if (path === '/pricing') {
priority = 0.8;
changefreq = 'weekly';
} else if (path === '/faq') {
priority = 0.6;
changefreq = 'weekly';
} else if (path.startsWith('/blog/')) {
priority = 0.6;
changefreq = 'weekly';
}
return {
loc: path,
changefreq,
priority,
lastmod: new Date().toISOString(),
};
},
};

View File

@ -27,11 +27,7 @@ const nextConfig = {
destination: '/blog/bulk-qr-code-generator-excel', destination: '/blog/bulk-qr-code-generator-excel',
permanent: true, permanent: true,
}, },
{
source: '/blog/bulk-qr-codes-excel',
destination: '/blog/bulk-qr-code-generator-excel',
permanent: true,
},
]; ];
}, },
}; };

View File

@ -6,6 +6,7 @@
"scripts": { "scripts": {
"dev": "next dev -p 3050", "dev": "next dev -p 3050",
"build": "prisma generate && next build", "build": "prisma generate && next build",
"submit:indexnow": "tsx scripts/submit-indexnow.ts",
"start": "next start", "start": "next start",
"lint": "next lint", "lint": "next lint",
"db:generate": "prisma generate", "db:generate": "prisma generate",

BIN
public/1234567890abcdef.txt Normal file

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.2 MiB

After

Width:  |  Height:  |  Size: 215 KiB

View File

@ -1,19 +0,0 @@
# QR Master - robots.txt
# Allow all search engines to crawl all pages
User-agent: *
Allow: /
# Sitemap location
Sitemap: https://www.qrmaster.net/sitemap.xml
# Crawl-delay (optional, be nice to servers)
Crawl-delay: 1
# Disallow admin/api routes
Disallow: /api/
Disallow: /dashboard/
Disallow: /_next/
# Allow all free tools explicitly
Allow: /tools/

View File

@ -1,33 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
<url>
<loc>https://www.qrmaster.net/</loc>
<lastmod>2025-10-16T00:00:00Z</lastmod>
<changefreq>daily</changefreq>
<priority>0.9</priority>
</url>
<url>
<loc>https://www.qrmaster.net/blog</loc>
<lastmod>2025-10-16T00:00:00Z</lastmod>
<changefreq>daily</changefreq>
<priority>0.7</priority>
</url>
<url>
<loc>https://www.qrmaster.net/pricing</loc>
<lastmod>2025-10-16T00:00:00Z</lastmod>
<changefreq>weekly</changefreq>
<priority>0.8</priority>
</url>
<url>
<loc>https://www.qrmaster.net/faq</loc>
<lastmod>2025-10-16T00:00:00Z</lastmod>
<changefreq>weekly</changefreq>
<priority>0.6</priority>
</url>
<url>
<loc>https://www.qrmaster.net/blog/qr-code-analytics</loc>
<lastmod>2025-10-16T00:00:00Z</lastmod>
<changefreq>weekly</changefreq>
<priority>0.6</priority>
</url>
</urlset>

View File

@ -0,0 +1,80 @@
import { blogPostList } from '../src/lib/blog-data';
import fs from 'fs';
import path from 'path';
const HOST = 'www.qrmaster.net';
const KEY = '1234567890abcdef';
const KEY_LOCATION = `https://${HOST}/${KEY}.txt`;
const INDEXNOW_ENDPOINT = 'https://api.indexnow.org/indexnow';
async function submitIndexNow() {
console.log('🚀 Starting IndexNow submission...');
// 1. Gather all URLs
const baseUrl = `https://${HOST}`;
const staticPages = [
'',
'/pricing',
'/faq',
'/blog',
'/signup',
'/login',
'/privacy',
'/qr-code-erstellen',
'/qr-code-tracking',
'/dynamic-qr-code-generator',
'/bulk-qr-code-generator',
'/newsletter',
];
// Dynamically get tool slugs from directory
const toolsDir = path.join(process.cwd(), 'src/app/(marketing)/tools');
let freeTools: string[] = [];
try {
freeTools = fs.readdirSync(toolsDir).filter(file => {
return fs.statSync(path.join(toolsDir, file)).isDirectory();
});
} catch (e) {
console.warn('⚠️ Could not read tools directory:', e);
}
const toolTypeUrls = freeTools.map(slug => `/tools/${slug}`);
const blogUrls = blogPostList.map(post => `/blog/${post.slug}`);
const allPaths = [...staticPages, ...toolTypeUrls, ...blogUrls];
const urlList = allPaths.map(path => `${baseUrl}${path}`);
console.log(`📝 Found ${urlList.length} URLs to submit.`);
// 2. Prepare payload
const payload = {
host: HOST,
key: KEY,
keyLocation: KEY_LOCATION,
urlList: urlList,
};
try {
// 3. Send Request
const response = await fetch(INDEXNOW_ENDPOINT, {
method: 'POST',
headers: {
'Content-Type': 'application/json; charset=utf-8',
},
body: JSON.stringify(payload),
});
if (response.status === 200 || response.status === 202) {
console.log('✅ IndexNow submission successful!');
} else {
console.error(`❌ IndexNow submission failed. Status: ${response.status}`);
console.error(await response.text());
}
} catch (error) {
console.error('❌ Error submitting to IndexNow:', error);
}
}
submitIndexNow();

View File

@ -1,6 +1,38 @@
Other
Structured data has schema.org validation error
38
4
3
1
0
0
Pages to submit to IndexNow
5
25
Issues Issues
/ /
H1 tag missing or empty Structured data has schema.org validation error
Why and how to fix Why and how to fix
@ -34,18 +66,20 @@ Crawl history
Hide chart Hide chart
12 Jan 12 Jan
13 Jan 13 Jan
13 Jan
14 Jan
0 0
1 10
2 20
3 30
4 40
All filter results All filter results
All filter results All filter results
2 38
Lost from filter results Lost from filter results
1 0
Lost Lost
0 0
@ -60,31 +94,418 @@ Export
PR PR
URL URL
Organic traffic Organic traffic
HTTP status code Schema items
Depth Structured data issues
H1
H1 length
No. of H1
Is indexable page Is indexable page
12 40
html html
Admin Dashboard | QR Master | QR Master QR Master: Dynamic QR Generator
https://www.qrmaster.net/
0
Organization
WebSite
Schema.org validation error
View issues
Yes
36
html
QR Code Erstellen Kostenlos | QR Master
https://www.qrmaster.net/qr-code-erstellen
0
Organization
WebSite
Schema.org validation error
View issues
Yes
35
html
Free SMS QR Code Generator | SMS QR Code Erstellen | QR Master
https://www.qrmaster.net/tools/sms-qr-code
0
Organization
WebSite
Schema.org validation error
View issues
Yes
35
html
Free Twitter (X) QR Code Generator | Follow & Connect | QR Master
https://www.qrmaster.net/tools/twitter-qr-code
0
Organization
WebSite
Schema.org validation error
View issues
Yes
35
html
Free WhatsApp QR Code Generator | Start Chats Instantly | QR Master
https://www.qrmaster.net/tools/whatsapp-qr-code
0
Organization
WebSite
Schema.org validation error
View issues
Yes
35
html
QR Insights: Latest QR Strategies | QR Master
https://www.qrmaster.net/blog
0
Organization
WebSite
Schema.org validation error
View issues
Yes
35
html
Free Event QR Code Generator | Termin & Kalender QR | QR Master
https://www.qrmaster.net/tools/event-qr-code
0
Organization
WebSite
Schema.org validation error
View issues
Yes
35
html
Free WiFi QR Code Generator | WLAN QR Code | QR Master
https://www.qrmaster.net/tools/wifi-qr-code
0
Organization
WebSite
Schema.org validation error
View issues
Yes
35
html
Privacy Policy | QR Master | QR Master
https://www.qrmaster.net/privacy
0
Organization
WebSite
Schema.org validation error
View issues
Yes
35
html
Free YouTube QR Code Generator | Get Views & Subscribers | QR Master
https://www.qrmaster.net/tools/youtube-qr-code
0
Organization
WebSite
Schema.org validation error
View issues
Yes
35
html
Pricing Plans | QR Master
https://www.qrmaster.net/pricing
0
Organization
WebSite
Schema.org validation error
View issues
Yes
35
html
Free Zoom QR Code Generator | Join Meetings Instantly | QR Master
https://www.qrmaster.net/tools/zoom-qr-code
0
Organization
WebSite
Schema.org validation error
View issues
Yes
35
html
Bulk QR Code Generator | Create from Excel | QR Master | QR Master
https://www.qrmaster.net/bulk-qr-code-generator
0
Organization
WebSite
Schema.org validation error
View issues
Yes
35
html
Bulk QR Codes from Excel: 2025 Guide | QR Master
https://www.qrmaster.net/blog/bulk-qr-code-generator-excel
0
BlogPosting
BreadcrumbList
HowTo
Organization
WebSite
Schema.org validation error
View issues
Yes
35
html
QR Master FAQ: Dynamic & Bulk QR | QR Master
https://www.qrmaster.net/faq
0
Organization
WebSite
Schema.org validation error
View issues
Yes
35
html
Free Geolocation QR Code Generator | Standort & Map Links | QR Master
https://www.qrmaster.net/tools/geolocation-qr-code
0
Organization
WebSite
Schema.org validation error
View issues
Yes
35
html
Free TikTok QR Code Generator | Get Followers | QR Master
https://www.qrmaster.net/tools/tiktok-qr-code
0
Organization
WebSite
Schema.org validation error
View issues
Yes
35
html
Free Instagram QR Code Generator | Get More Followers | QR Master
https://www.qrmaster.net/tools/instagram-qr-code
0
Organization
WebSite
Schema.org validation error
View issues
Yes
35
html
Free Phone QR Code Generator | Anruf & Telefon QR | QR Master
https://www.qrmaster.net/tools/phone-qr-code
0
Organization
WebSite
Schema.org validation error
View issues
Yes
35
html
Free Facebook QR Code Generator | Get Likes & Follows | QR Master
https://www.qrmaster.net/tools/facebook-qr-code
0
Organization
WebSite
Schema.org validation error
View issues
Yes
35
html
Free Microsoft Teams QR Code Generator | Join Meetings | QR Master
https://www.qrmaster.net/tools/teams-qr-code
0
Organization
WebSite
Schema.org validation error
View issues
Yes
35
html
Free PayPal QR Code Generator | Accept Payments Instantly | QR Master
https://www.qrmaster.net/tools/paypal-qr-code
0
Organization
WebSite
Schema.org validation error
View issues
Yes
35
html
Free URL QR Code Generator | Link to Any Website | QR Master
https://www.qrmaster.net/tools/url-qr-code
0
Organization
WebSite
Schema.org validation error
View issues
Yes
35
html
Free Email QR Code Generator | Email QR Code Erstellen | QR Master
https://www.qrmaster.net/tools/email-qr-code
0
Organization
WebSite
Schema.org validation error
View issues
Yes
35
html
Free vCard QR Code Generator | Digitale Visitenkarte Erstellen | QR Master
https://www.qrmaster.net/tools/vcard-qr-code
0
Organization
WebSite
Schema.org validation error
View issues
Yes
35
html
Free Text QR Code Generator | Text zu QR Code | QR Master
https://www.qrmaster.net/tools/text-qr-code
0
Organization
WebSite
Schema.org validation error
View issues
Yes
35
html
Free Crypto QR Code Generator | Krypto QR Code Erstellen | QR Master
https://www.qrmaster.net/tools/crypto-qr-code
0
Organization
WebSite
Schema.org validation error
View issues
Yes
33
html
Free vCard QR Generator: Digital Cards | QR Master
https://www.qrmaster.net/blog/vcard-qr-code-generator
0
BlogPosting
BreadcrumbList
HowTo
Organization
WebSite
Schema.org validation error
View issues
Yes
33
html
Restaurant Menu QR Codes: 2025 Guide | QR Master
https://www.qrmaster.net/blog/qr-code-restaurant-menu
0
BlogPosting
BreadcrumbList
HowTo
Organization
WebSite
Schema.org validation error
View issues
Yes
33
html
QR Code Analytics: The Complete Guide | QR Master
https://www.qrmaster.net/blog/qr-code-analytics
0
BlogPosting
BreadcrumbList
HowTo
Organization
WebSite
Schema.org validation error
View issues
Yes
33
html
Static vs Dynamic QR Codes: The Ultimate Guide (2025) | QR Master
https://www.qrmaster.net/blog/dynamic-vs-static-qr-codes
0
BlogPosting
BreadcrumbList
Organization
WebSite
Schema.org validation error
View issues
Yes
33
html
QR Code Print Size Guide: Minimum Sizes for Every Use Case | QR Master
https://www.qrmaster.net/blog/qr-code-print-size-guide
0
BlogPosting
BreadcrumbList
Organization
WebSite
Schema.org validation error
View issues
Yes
33
html
Best QR Code Generator for Small Business 2025 | QR Master
https://www.qrmaster.net/blog/qr-code-small-business
0
BlogPosting
BreadcrumbList
Organization
WebSite
Schema.org validation error
View issues
Yes
33
html
QR Code Tracking: Complete Guide 2025 | QR Master
https://www.qrmaster.net/blog/qr-code-tracking-guide-2025
0
BlogPosting
BreadcrumbList
HowTo
Organization
WebSite
Schema.org validation error
View issues
Yes
27
html
Dynamic QR Code Generator | Edit & Track QR | QR Master | QR Master
https://www.qrmaster.net/dynamic-qr-code-generator
0
Organization
WebSite
Schema.org validation error
View issues
Yes
22
html
QR Code Tracking & Analytics - Track Every Scan | QR Master | QR Master
https://www.qrmaster.net/qr-code-tracking
0
Organization
WebSite
Schema.org validation error
View issues
Yes
15
html
Newsletter Admin | QR Master | QR Master
https://www.qrmaster.net/newsletter https://www.qrmaster.net/newsletter
0 0
200 Organization
1 WebSite
0 Schema.org validation error
View issues
No No
2 2
html html
Post Not Found | QR Master QR Master Smart QR Generator & Analytics
https://www.qrmaster.net/blog/3-body.png https://www.qrmaster.net/blog/3-body.png
0 0
200 Organization
2 WebSite
0 Schema.org validation error
View issues
No No
Showing 2 of 2 Showing 38 of 38
@ -100,7 +521,7 @@ Showing 2 of 2
Issues Issues
/ /
Low word count Pages to submit to IndexNow
Why and how to fix Why and how to fix
@ -134,25 +555,25 @@ Crawl history
Hide chart Hide chart
12 Jan 12 Jan
13 Jan 13 Jan
13 Jan
14 Jan
0 0
1 8
2 16
3 24
4 32
All filter results All filter results
All filter results All filter results
2 5
Lost from filter results Lost from filter results
1
Lost Lost
0
Patches: Show all Patches: Show all
Changes: Don't show Changes: Absolute
Columns Columns
@ -160,8 +581,10 @@ Export
PR PR
URL URL
Organic traffic Organic traffic
Depth Changes
No. of content words HTTP status code
Content type
Is indexable page
Title Title
Patch it Patch it
@ -171,141 +594,149 @@ Patch it
Batch AI Batch AI
H1 H1
Is indexable page H2
12 No. of content words
Changes
No. of internal outlinks
Changes
No. of external outlinks
Changes
Page text
First found at
35
html html
Admin Dashboard | QR Master | QR Master Free WiFi QR Code Generator | WLAN QR Code | QR Master
https://www.qrmaster.net/newsletter https://www.qrmaster.net/tools/wifi-qr-code
0
1
8
Admin Dashboard | QR Master | QR Master
Enter new title
Admin restricted area.
Enter new meta description
No
2
html
Post Not Found | QR Master
https://www.qrmaster.net/blog/3-body.png
0
2
6
Post Not Found | QR Master
Enter new title
Create dynamic QR codes, track scans, and scale campaigns with secure analytics.
Enter new meta description
No
Showing 2 of 2
Issues
/
Meta description too short
Why and how to fix
Submit to IndexNow
Create new issue
All URLs
Pages
Resources
Content
Links
Redirects
Indexability
Sitemaps
Ahrefs metrics
Word or phrase
URL
Advanced filter
Crawl history
Hide chart
12 Jan
13 Jan
0
1
2
3
4
All filter results
All filter results
2
Lost from filter results
1
Lost
0
Patches: Show all
Changes: Don't show
Columns
Export
PR
URL
Organic traffic
HTTP status code
Depth
Meta description
Patch it
Batch AI
Meta description length
No. of meta descriptions
Is indexable page
12
html
Admin Dashboard | QR Master | QR Master
https://www.qrmaster.net/newsletter
0 0
200 200
1 text/html; charset=utf-8
Admin restricted area. Yes
Free WiFi QR Code Generator | WLAN QR Code | QR Master
Free WiFi QR Code Generator | WLAN QR Code Erstellen | QR Master
Enter new title
Create a WiFi QR code in seconds. Erstelle kostenlos deinen WLAN QR Code ohne Passwort-Eingabe. Guests scan to connect instantly. 100% Secure & Free.
Enter new meta description Enter new meta description
12
13
1
0
0
View changes
54 B
64 B
https://www.qrmaster.net/blog/qr-code-analytics
33
html
Free vCard QR Generator: Digital Cards | QR Master
https://www.qrmaster.net/blog/vcard-qr-code-generator
0
200
308
text/html; charset=utf-8
text/plain; charset=utf-8
Yes
No
Free vCard QR Generator: Digital Cards | QR Master
Enter new title
Create professional vCard QR codes for digital business cards. Share contact info instantly with a scan—includes templates and best practices.
Enter new meta description
Free vCard QR Generator: Digital Cards
Quick Answer
What is a vCard QR Code?
Why Use a Digital Business Card QR Code?
Information You Can Include in a vCard
Static vs Dynamic vCard QR Codes
All 13
1,149
0
+1,149
36
0
+36
0
View text
7 KB
https://www.qrmaster.net/blog/qr-code-analytics
33
html
Restaurant Menu QR Codes: 2025 Guide | QR Master
https://www.qrmaster.net/blog/qr-code-restaurant-menu
0
200
308
text/html; charset=utf-8
text/plain; charset=utf-8
Yes
No
Restaurant Menu QR Codes: 2025 Guide | QR Master
Enter new title
Step-by-step guide to creating digital menu QR codes for your restaurant. Learn best practices for touchless menus, placement tips, and tracking.
Enter new meta description
Restaurant Menu QR Codes: 2025 Guide
Quick Answer
Why Restaurants Need QR Code Menus in 2025
Step 1: Prepare Your Digital Menu
Step 2: Create Your QR Code with QR Master
Step 3: Customize Your Restaurant QR Code
All 13
1,256
0
+1,256
38
0
+38
0
View text
8 KB
https://www.qrmaster.net/blog/qr-code-analytics
33
html
Best QR Code Generator for Small Business 2025 | QR Master
https://www.qrmaster.net/blog/qr-code-small-business
0
200
308
text/html; charset=utf-8
text/plain; charset=utf-8
Yes
No
Best QR Code Generator for Small Business 2025 | QR Master
Enter new title
Find the best QR code solution for your small business. Compare features, pricing, and use cases for marketing, payments, and operations.
Enter new meta description
Best QR Code Generator for Small Business 2025
Quick Answer
Why Small Businesses Need QR Codes
Top 10 QR Code Use Cases for Small Business
What to Look for in a Small Business QR Solution
QR Master for Small Business
All 11
1,048
0
+1,048
36
0
+36
0
View text
7 KB
https://www.qrmaster.net/blog/qr-code-analytics
22 22
1
No
2
html html
Post Not Found | QR Master QR Code Tracking & Analytics - Track Every Scan | QR Master | QR Master
https://www.qrmaster.net/blog/3-body.png https://www.qrmaster.net/qr-code-tracking
0 0
200 200
2 text/html; charset=utf-8
Create dynamic QR codes, track scans, and scale campaigns with secure analytics. Yes
QR Code Tracking & Analytics - Track Every Scan | QR Master | QR Master
Enter new title
Track QR code scans with real-time analytics. Monitor location, device, time, and user behavior. Free QR code tracking software with detailed reports.
Enter new meta description Enter new meta description
80 15
1 0
No 0
Showing 2 of 2 View text
71 B
https://www.qrmaster.net/blog/qr-code-restaurant-menu
Showing 5 of 5

View File

@ -1,5 +1,6 @@
import type { Metadata } from 'next'; import type { Metadata } from 'next';
import '@/styles/globals.css'; import '@/styles/globals.css';
import { Suspense } from 'react';
import { Providers } from '@/components/Providers'; import { Providers } from '@/components/Providers';
import AppLayout from './AppLayout'; import AppLayout from './AppLayout';
@ -18,9 +19,11 @@ export default function RootAppLayout({
<html lang="en"> <html lang="en">
<body className="font-sans"> <body className="font-sans">
<Providers> <Providers>
<AppLayout> <Suspense fallback={null}>
{children} <AppLayout>
</AppLayout> {children}
</AppLayout>
</Suspense>
</Providers> </Providers>
</body> </body>
</html> </html>

View File

@ -5,7 +5,7 @@ import type { Metadata } from 'next';
export const metadata: Metadata = { export const metadata: Metadata = {
title: 'Authentication | QR Master', title: 'Authentication | QR Master',
description: 'Securely login or sign up to QR Master to manage your dynamic QR codes, track analytics, and access premium features. Your gateway to professional QR management.', description: 'Securely login or sign up to QR Master to manage your dynamic QR codes, track analytics, and access premium features. Your gateway to professional QR management.',
robots: { index: false, follow: true },
}; };
export default function AuthRootLayout({ export default function AuthRootLayout({
@ -19,6 +19,11 @@ export default function AuthRootLayout({
<Providers> <Providers>
<div className="min-h-screen bg-gradient-to-br from-primary-50 to-white"> <div className="min-h-screen bg-gradient-to-br from-primary-50 to-white">
{children} {children}
<div className="py-6 text-center text-sm text-slate-500 space-x-4">
<a href="/" className="hover:text-primary-600 transition-colors">Home</a>
<a href="/privacy" className="hover:text-primary-600 transition-colors">Privacy</a>
<a href="/faq" className="hover:text-primary-600 transition-colors">FAQ</a>
</div>
</div> </div>
</Providers> </Providers>
</body> </body>

View File

@ -72,116 +72,93 @@ export default function LoginClientPage() {
}; };
return ( return (
<div className="min-h-screen bg-gradient-to-br from-primary-50 to-white flex items-center justify-center p-4"> <Card>
<div className="w-full max-w-md"> <CardContent className="p-6">
<div className="text-center mb-8"> <form onSubmit={handleSubmit} className="space-y-4">
<Link href="/" className="inline-flex items-center space-x-2 mb-6"> {error && (
<img src="/logo.svg" alt="QR Master" className="w-10 h-10" /> <div className="bg-red-50 text-red-600 p-3 rounded-lg text-sm">
<span className="text-2xl font-bold text-gray-900">QR Master</span> {error}
</Link>
<h1 className="text-3xl font-bold text-gray-900">Welcome Back</h1>
<p className="text-gray-600 mt-2">Sign in to your account</p>
<Link href="/" className="text-sm text-primary-600 hover:text-primary-700 font-medium mt-2 inline-block border border-primary-600 hover:border-primary-700 px-4 py-2 rounded-lg transition-colors">
Back to Home
</Link>
</div>
<Card>
<CardContent className="p-6">
<form onSubmit={handleSubmit} className="space-y-4">
{error && (
<div className="bg-red-50 text-red-600 p-3 rounded-lg text-sm">
{error}
</div>
)}
<Input
label="Email"
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="you@example.com"
required
/>
<Input
label="Password"
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="••••••••"
required
/>
<div className="flex items-center justify-between">
<label className="flex items-center">
<input type="checkbox" className="mr-2" />
<span className="text-sm text-gray-600">Remember me</span>
</label>
<Link href="/forgot-password" className="text-sm text-primary-600 hover:text-primary-700">
Forgot password?
</Link>
</div>
<Button type="submit" className="w-full" loading={loading} disabled={csrfLoading || loading}>
{csrfLoading ? 'Loading...' : 'Sign In'}
</Button>
<div className="relative my-6">
<div className="absolute inset-0 flex items-center">
<div className="w-full border-t border-gray-300"></div>
</div>
<div className="relative flex justify-center text-sm">
<span className="px-2 bg-white text-gray-500">Or continue with</span>
</div>
</div>
<Button
type="button"
variant="outline"
className="w-full"
onClick={handleGoogleSignIn}
>
<svg className="w-5 h-5 mr-2" viewBox="0 0 24 24">
<path
fill="#4285F4"
d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"
/>
<path
fill="#34A853"
d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"
/>
<path
fill="#FBBC05"
d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"
/>
<path
fill="#EA4335"
d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"
/>
</svg>
Sign in with Google
</Button>
</form>
<div className="mt-6 text-center">
<p className="text-sm text-gray-600">
Don't have an account?{' '}
<Link href="/signup" className="text-primary-600 hover:text-primary-700 font-medium">
Sign up
</Link>
</p>
</div> </div>
</CardContent> )}
</Card>
<p className="text-center text-sm text-gray-500 mt-6"> <Input
By signing in, you agree to our{' '} label="Email"
<Link href="/privacy" className="text-primary-600 hover:text-primary-700"> type="email"
Privacy Policy value={email}
</Link> onChange={(e) => setEmail(e.target.value)}
</p> placeholder="you@example.com"
</div> required
</div> />
<Input
label="Password"
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="••••••••"
required
/>
<div className="flex items-center justify-between">
<label className="flex items-center">
<input type="checkbox" className="mr-2" />
<span className="text-sm text-gray-600">Remember me</span>
</label>
<Link href="/forgot-password" className="text-sm text-primary-600 hover:text-primary-700">
Forgot password?
</Link>
</div>
<Button type="submit" className="w-full" loading={loading} disabled={csrfLoading || loading}>
{csrfLoading ? 'Loading...' : 'Sign In'}
</Button>
<div className="relative my-6">
<div className="absolute inset-0 flex items-center">
<div className="w-full border-t border-gray-300"></div>
</div>
<div className="relative flex justify-center text-sm">
<span className="px-2 bg-white text-gray-500">Or continue with</span>
</div>
</div>
<Button
type="button"
variant="outline"
className="w-full"
onClick={handleGoogleSignIn}
>
<svg className="w-5 h-5 mr-2" viewBox="0 0 24 24">
<path
fill="#4285F4"
d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"
/>
<path
fill="#34A853"
d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"
/>
<path
fill="#FBBC05"
d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"
/>
<path
fill="#EA4335"
d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"
/>
</svg>
Sign in with Google
</Button>
</form>
<div className="mt-6 text-center">
<p className="text-sm text-gray-600">
Don't have an account?{' '}
<Link href="/signup" className="text-primary-600 hover:text-primary-700 font-medium">
Sign up
</Link>
</p>
</div>
</CardContent>
</Card>
); );
} }

View File

@ -1,5 +1,6 @@
import React from 'react'; import React, { Suspense } from 'react';
import type { Metadata } from 'next'; import type { Metadata } from 'next';
import Link from 'next/link';
import LoginClientPage from './ClientPage'; import LoginClientPage from './ClientPage';
export const metadata: Metadata = { export const metadata: Metadata = {
@ -12,16 +13,38 @@ export const metadata: Metadata = {
}, },
}; };
export default function LoginPage() { export default function LoginPage() {
return ( return (
<> <div className="min-h-screen bg-gradient-to-br from-primary-50 to-white flex items-center justify-center p-4">
<h1 className="sr-only">Login to QR Master Create & Track QR Codes</h1> <div className="w-full max-w-md">
<div className="sr-only"> <div className="text-center mb-8">
<h2>Secure Dashboard Access</h2> <Link href="/" className="inline-flex items-center space-x-2 mb-6">
<p>Log in to manage your dynamic QR codes, view scan analytics, and update destination URLs instantly.</p> <img src="/logo.svg" alt="QR Master" className="w-10 h-10" />
<a href="/">Back to Home</a> <span className="text-2xl font-bold text-gray-900">QR Master</span>
</Link>
<h1 className="text-3xl font-bold text-gray-900">Welcome Back</h1>
<p className="text-gray-600 mt-2">Sign in to your account</p>
<Link href="/" className="text-sm text-primary-600 hover:text-primary-700 font-medium mt-2 inline-block border border-primary-600 hover:border-primary-700 px-4 py-2 rounded-lg transition-colors">
Back to Home
</Link>
</div>
<Suspense fallback={
<div className="bg-white rounded-xl shadow-sm border border-slate-200 p-8 flex items-center justify-center min-h-[400px]">
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-primary-600"></div>
</div>
}>
<LoginClientPage />
</Suspense>
<p className="text-center text-sm text-gray-500 mt-6">
By signing in, you agree to our{' '}
<Link href="/privacy" className="text-primary-600 hover:text-primary-700">
Privacy Policy
</Link>
</p>
</div> </div>
<LoginClientPage /> </div>
</>
); );
} }

View File

@ -8,7 +8,9 @@ import { Input } from '@/components/ui/Input';
import { Button } from '@/components/ui/Button'; import { Button } from '@/components/ui/Button';
import { useCsrf } from '@/hooks/useCsrf'; import { useCsrf } from '@/hooks/useCsrf';
export default function ResetPasswordPage() { import { Suspense } from 'react';
function ResetPasswordContent() {
const { fetchWithCsrf, loading: csrfLoading } = useCsrf(); const { fetchWithCsrf, loading: csrfLoading } = useCsrf();
const searchParams = useSearchParams(); const searchParams = useSearchParams();
const router = useRouter(); const router = useRouter();
@ -206,3 +208,11 @@ export default function ResetPasswordPage() {
</div> </div>
); );
} }
export default function ResetPasswordPage() {
return (
<Suspense fallback={<div className="min-h-screen flex items-center justify-center">Loading...</div>}>
<ResetPasswordContent />
</Suspense>
);
}

View File

@ -85,124 +85,101 @@ export default function SignupClientPage() {
}; };
return ( return (
<div className="min-h-screen bg-gradient-to-br from-primary-50 to-white flex items-center justify-center p-4"> <Card>
<div className="w-full max-w-md"> <CardContent className="p-6">
<div className="text-center mb-8"> <form onSubmit={handleSubmit} className="space-y-4">
<Link href="/" className="inline-flex items-center space-x-2 mb-6"> {error && (
<img src="/logo.svg" alt="QR Master" className="w-10 h-10" /> <div className="bg-red-50 text-red-600 p-3 rounded-lg text-sm">
<span className="text-2xl font-bold text-gray-900">QR Master</span> {error}
</Link>
<h1 className="text-3xl font-bold text-gray-900">Create Account</h1>
<p className="text-gray-600 mt-2">Start creating QR codes in seconds</p>
<Link href="/" className="text-sm text-primary-600 hover:text-primary-700 font-medium mt-2 inline-block border border-primary-600 hover:border-primary-700 px-4 py-2 rounded-lg transition-colors">
Back to Home
</Link>
</div>
<Card>
<CardContent className="p-6">
<form onSubmit={handleSubmit} className="space-y-4">
{error && (
<div className="bg-red-50 text-red-600 p-3 rounded-lg text-sm">
{error}
</div>
)}
<Input
label="Full Name"
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="John Doe"
required
/>
<Input
label="Email"
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="you@example.com"
required
/>
<Input
label="Password"
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="••••••••"
required
/>
<Input
label="Confirm Password"
type="password"
value={confirmPassword}
onChange={(e) => setConfirmPassword(e.target.value)}
placeholder="••••••••"
required
/>
<Button type="submit" className="w-full" loading={loading}>
Create Account
</Button>
<div className="relative my-6">
<div className="absolute inset-0 flex items-center">
<div className="w-full border-t border-gray-300"></div>
</div>
<div className="relative flex justify-center text-sm">
<span className="px-2 bg-white text-gray-500">Or continue with</span>
</div>
</div>
<Button
type="button"
variant="outline"
className="w-full"
onClick={handleGoogleSignIn}
>
<svg className="w-5 h-5 mr-2" viewBox="0 0 24 24">
<path
fill="#4285F4"
d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"
/>
<path
fill="#34A853"
d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"
/>
<path
fill="#FBBC05"
d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"
/>
<path
fill="#EA4335"
d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"
/>
</svg>
Sign up with Google
</Button>
</form>
<div className="mt-6 text-center">
<p className="text-sm text-gray-600">
Already have an account?{' '}
<Link href="/login" className="text-primary-600 hover:text-primary-700 font-medium">
Sign in
</Link>
</p>
</div> </div>
</CardContent> )}
</Card>
<p className="text-center text-sm text-gray-500 mt-6"> <Input
By signing up, you agree to our{' '} label="Full Name"
<Link href="/privacy" className="text-primary-600 hover:text-primary-700"> type="text"
Privacy Policy value={name}
</Link> onChange={(e) => setName(e.target.value)}
</p> placeholder="John Doe"
</div> required
</div> />
<Input
label="Email"
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="you@example.com"
required
/>
<Input
label="Password"
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="••••••••"
required
/>
<Input
label="Confirm Password"
type="password"
value={confirmPassword}
onChange={(e) => setConfirmPassword(e.target.value)}
placeholder="••••••••"
required
/>
<Button type="submit" className="w-full" loading={loading}>
Create Account
</Button>
<div className="relative my-6">
<div className="absolute inset-0 flex items-center">
<div className="w-full border-t border-gray-300"></div>
</div>
<div className="relative flex justify-center text-sm">
<span className="px-2 bg-white text-gray-500">Or continue with</span>
</div>
</div>
<Button
type="button"
variant="outline"
className="w-full"
onClick={handleGoogleSignIn}
>
<svg className="w-5 h-5 mr-2" viewBox="0 0 24 24">
<path
fill="#4285F4"
d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92c-.26 1.37-1.04 2.53-2.21 3.31v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.09z"
/>
<path
fill="#34A853"
d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z"
/>
<path
fill="#FBBC05"
d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18C1.43 8.55 1 10.22 1 12s.43 3.45 1.18 4.93l2.85-2.22.81-.62z"
/>
<path
fill="#EA4335"
d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z"
/>
</svg>
Sign up with Google
</Button>
</form>
<div className="mt-6 text-center">
<p className="text-sm text-gray-600">
Already have an account?{' '}
<Link href="/login" className="text-primary-600 hover:text-primary-700 font-medium">
Sign in
</Link>
</p>
</div>
</CardContent>
</Card>
); );
} }

View File

@ -1,5 +1,6 @@
import React from 'react'; import React, { Suspense } from 'react';
import type { Metadata } from 'next'; import type { Metadata } from 'next';
import Link from 'next/link';
import SignupClientPage from './ClientPage'; import SignupClientPage from './ClientPage';
export const metadata: Metadata = { export const metadata: Metadata = {
@ -12,16 +13,39 @@ export const metadata: Metadata = {
}, },
}; };
export default function SignupPage() { export default function SignupPage() {
return ( return (
<> <div className="min-h-screen bg-gradient-to-br from-primary-50 to-white flex items-center justify-center p-4">
<h1 className="sr-only">Sign Up for QR Master Free QR Code Generator</h1> <div className="w-full max-w-md">
<div className="sr-only"> <div className="text-center mb-8">
<h2>Get Started Free</h2> <Link href="/" className="inline-flex items-center space-x-2 mb-6">
<p>Create your account today. No credit card required for the free tier. Start generating trackable QR codes in minutes.</p> <img src="/logo.svg" alt="QR Master" className="w-10 h-10" />
<a href="/">Back to Home</a> <span className="text-2xl font-bold text-gray-900">QR Master</span>
</Link>
<h1 className="text-3xl font-bold text-gray-900">Create Account</h1>
<p className="text-gray-600 mt-2">Start creating QR codes in seconds</p>
<Link href="/" className="text-sm text-primary-600 hover:text-primary-700 font-medium mt-2 inline-block border border-primary-600 hover:border-primary-700 px-4 py-2 rounded-lg transition-colors">
Back to Home
</Link>
</div>
<Suspense fallback={
<div className="bg-white rounded-xl shadow-sm border border-slate-200 p-8 flex items-center justify-center min-h-[500px]">
<div className="animate-spin rounded-full h-8 w-8 border-b-2 border-primary-600"></div>
</div>
}>
<SignupClientPage />
</Suspense>
<p className="text-center text-sm text-gray-500 mt-6">
By signing up, you agree to our{' '}
<Link href="/privacy" className="text-primary-600 hover:text-primary-700">
Privacy Policy
</Link>
</p>
</div> </div>
<SignupClientPage /> </div>
</>
); );
} }

File diff suppressed because it is too large Load Diff

View File

@ -7,6 +7,7 @@ import { websiteSchema, breadcrumbSchema } from '@/lib/schema';
import { Card, CardHeader, CardTitle, CardContent } from '@/components/ui/Card'; import { Card, CardHeader, CardTitle, CardContent } from '@/components/ui/Card';
import { Badge } from '@/components/ui/Badge'; import { Badge } from '@/components/ui/Badge';
import Breadcrumbs, { BreadcrumbItem } from '@/components/Breadcrumbs'; import Breadcrumbs, { BreadcrumbItem } from '@/components/Breadcrumbs';
import { blogPostList } from '@/lib/blog-data';
function truncateAtWord(text: string, maxLength: number): string { function truncateAtWord(text: string, maxLength: number): string {
if (text.length <= maxLength) return text; if (text.length <= maxLength) return text;
@ -37,6 +38,14 @@ export async function generateMetadata(): Promise<Metadata> {
description, description,
url: 'https://www.qrmaster.net/blog', url: 'https://www.qrmaster.net/blog',
type: 'website', type: 'website',
images: [
{
url: 'https://www.qrmaster.net/og-image.png',
width: 1200,
height: 630,
alt: 'QR Insights - QR Code Marketing & Analytics Blog',
},
],
}, },
twitter: { twitter: {
title, title,
@ -45,82 +54,7 @@ export async function generateMetadata(): Promise<Metadata> {
}; };
} }
const blogPosts = [
// NEW POSTS (January 2026)
{
slug: 'qr-code-restaurant-menu',
title: 'How to Create a QR Code for Restaurant Menu',
excerpt: 'Step-by-step guide to creating digital menu QR codes for your restaurant. Learn best practices for touchless menus, placement tips, and tracking.',
date: 'January 5, 2026',
readTime: '12 Min',
category: 'Restaurant',
image: '/blog/restaurant-qr-menu.png',
},
{
slug: 'vcard-qr-code-generator',
title: 'Free vCard QR Code Generator: Digital Business Cards',
excerpt: 'Create professional vCard QR codes for digital business cards. Share contact info instantly with a scan—includes templates and best practices.',
date: 'January 5, 2026',
readTime: '10 Min',
category: 'Business Cards',
image: '/blog/vcard-qr-code.png',
},
{
slug: 'qr-code-small-business',
title: 'Best QR Code Generator for Small Business: 2025 Guide',
excerpt: 'Find the best QR code solution for your small business. Compare features, pricing, and use cases for marketing, payments, and operations.',
date: 'January 5, 2026',
readTime: '14 Min',
category: 'Business',
image: '/blog/small-business-qr.png',
},
{
slug: 'qr-code-print-size-guide',
title: 'QR Code Print Size Guide: Minimum Sizes for Every Use Case',
excerpt: 'Complete guide to QR code print sizes. Learn minimum dimensions for business cards, posters, banners, and more to ensure reliable scanning.',
date: 'January 5, 2026',
readTime: '8 Min',
category: 'Printing',
image: '/blog/qr-print-sizes.png',
},
// EXISTING POSTS
{
slug: 'qr-code-tracking-guide-2025',
title: 'QR Code Tracking: Complete Guide 2025',
excerpt: 'Learn how to track QR code scans with real-time analytics. Compare free vs paid tracking tools, setup Google Analytics, and measure ROI.',
date: 'October 18, 2025',
readTime: '12 Min',
category: 'Tracking & Analytics',
image: '/blog/1-hero.png',
},
{
slug: 'dynamic-vs-static-qr-codes',
title: 'Dynamic vs Static QR Codes: Which Should You Use?',
excerpt: 'Understand the difference between static and dynamic QR codes. Learn when to use each type, pros/cons, and how dynamic QR codes save money.',
date: 'October 17, 2025',
readTime: '10 Min',
category: 'QR Code Basics',
image: '/blog/2-hero.png',
},
{
slug: 'bulk-qr-code-generator-excel',
title: 'How to Generate Bulk QR Codes from Excel',
excerpt: 'Generate hundreds of QR codes from Excel or CSV files in minutes. Step-by-step guide with templates, best practices, and free tools.',
date: 'October 16, 2025',
readTime: '13 Min',
category: 'Bulk Generation',
image: '/blog/3-hero.png',
},
{
slug: 'qr-code-analytics',
title: 'QR Code Analytics: Track, Measure & Optimize Campaigns',
excerpt: 'Learn how to leverage scan analytics, campaign tracking, and dashboard insights to maximize QR code ROI.',
date: 'October 16, 2025',
readTime: '15 Min',
category: 'Analytics',
image: '/blog/4-hero.png',
},
];
export default function BlogPage() { export default function BlogPage() {
const breadcrumbItems: BreadcrumbItem[] = [ const breadcrumbItems: BreadcrumbItem[] = [
@ -145,7 +79,7 @@ export default function BlogPage() {
</div> </div>
<div className="grid md:grid-cols-2 lg:grid-cols-3 gap-8 max-w-6xl mx-auto"> <div className="grid md:grid-cols-2 lg:grid-cols-3 gap-8 max-w-6xl mx-auto">
{blogPosts.map((post: any) => ( {blogPostList.map((post: any) => (
<Link key={post.slug} href={post.link || `/blog/${post.slug}`}> <Link key={post.slug} href={post.link || `/blog/${post.slug}`}>
<Card hover className="h-full overflow-hidden shadow-md hover:shadow-xl transition-all duration-300"> <Card hover className="h-full overflow-hidden shadow-md hover:shadow-xl transition-all duration-300">
<div className="relative h-56 overflow-hidden"> <div className="relative h-56 overflow-hidden">

View File

@ -23,6 +23,14 @@ export const metadata: Metadata = {
description: 'Generate hundreds of QR codes at once from CSV or Excel files. Perfect for products, events, and inventory.', description: 'Generate hundreds of QR codes at once from CSV or Excel files. Perfect for products, events, and inventory.',
url: 'https://www.qrmaster.net/bulk-qr-code-generator', url: 'https://www.qrmaster.net/bulk-qr-code-generator',
type: 'website', type: 'website',
images: [
{
url: 'https://www.qrmaster.net/og-image.png',
width: 1200,
height: 630,
alt: 'Bulk QR Code Generator - QR Master',
},
],
}, },
twitter: { twitter: {
title: 'Bulk QR Code Generator - Create 1000s of QR Codes from Excel', title: 'Bulk QR Code Generator - Create 1000s of QR Codes from Excel',

View File

@ -23,6 +23,14 @@ export const metadata: Metadata = {
description: 'Create dynamic QR codes that can be edited after printing. Change URLs, track scans, and update content anytime.', description: 'Create dynamic QR codes that can be edited after printing. Change URLs, track scans, and update content anytime.',
url: 'https://www.qrmaster.net/dynamic-qr-code-generator', url: 'https://www.qrmaster.net/dynamic-qr-code-generator',
type: 'website', type: 'website',
images: [
{
url: 'https://www.qrmaster.net/og-image.png',
width: 1200,
height: 630,
alt: 'Dynamic QR Code Generator - QR Master',
},
],
}, },
twitter: { twitter: {
title: 'Dynamic QR Code Generator - Edit QR Codes Anytime | QR Master', title: 'Dynamic QR Code Generator - Edit QR Codes Anytime | QR Master',

View File

@ -33,6 +33,14 @@ export async function generateMetadata(): Promise<Metadata> {
description, description,
url: 'https://www.qrmaster.net/faq', url: 'https://www.qrmaster.net/faq',
type: 'website', type: 'website',
images: [
{
url: 'https://www.qrmaster.net/og-image.png',
width: 1200,
height: 630,
alt: 'QR Master FAQ',
},
],
}, },
twitter: { twitter: {
title, title,

View File

@ -199,8 +199,8 @@ export default function NewsletterClient() {
<p className="text-muted-foreground text-sm"> <p className="text-muted-foreground text-sm">
Sign in to access admin panel Sign in to access admin panel
</p> </p>
<Link href="/" className="sr-only"> <Link href="/" className="text-sm text-slate-500 hover:text-slate-900 block mt-2">
Back to Home Back to Home
</Link> </Link>
</div> </div>

View File

@ -14,6 +14,20 @@ export const metadata: Metadata = {
index: true, index: true,
follow: true, follow: true,
}, },
openGraph: {
title: 'Pricing Plans | QR Master',
description: 'Choose the perfect QR code plan for your needs.',
url: 'https://www.qrmaster.net/pricing',
type: 'website',
images: [
{
url: 'https://www.qrmaster.net/og-image.png',
width: 1200,
height: 630,
alt: 'QR Master Pricing Plans',
},
],
},
}; };
export default function PricingPage() { export default function PricingPage() {

View File

@ -4,6 +4,23 @@ import Link from 'next/link';
export const metadata = { export const metadata = {
title: 'Privacy Policy | QR Master', title: 'Privacy Policy | QR Master',
description: 'Read our Privacy Policy to understand how QR Master collects, uses, and protects your data. We are committed to GDPR compliance and data security.', description: 'Read our Privacy Policy to understand how QR Master collects, uses, and protects your data. We are committed to GDPR compliance and data security.',
alternates: {
canonical: 'https://www.qrmaster.net/privacy',
},
openGraph: {
title: 'Privacy Policy | QR Master',
description: 'Read our Privacy Policy to understand how QR Master collects, uses, and protects your data.',
url: 'https://www.qrmaster.net/privacy',
type: 'website',
images: [
{
url: 'https://www.qrmaster.net/og-image.png',
width: 1200,
height: 630,
alt: 'QR Master Privacy Policy',
},
],
},
}; };
export default function PrivacyPage() { export default function PrivacyPage() {

View File

@ -8,7 +8,7 @@ import Breadcrumbs, { BreadcrumbItem } from '@/components/Breadcrumbs';
import { breadcrumbSchema } from '@/lib/schema'; import { breadcrumbSchema } from '@/lib/schema';
export const metadata: Metadata = { export const metadata: Metadata = {
title: 'QR Code Tracking & Analytics - Track Every Scan | QR Master', title: 'QR Code Tracking & Analytics - Track Scans',
description: 'Track QR code scans with real-time analytics. Monitor location, device, time, and user behavior. Free QR code tracking software with detailed reports.', description: 'Track QR code scans with real-time analytics. Monitor location, device, time, and user behavior. Free QR code tracking software with detailed reports.',
keywords: 'qr code tracking, qr code analytics, track qr scans, qr code statistics, free qr tracking, qr code monitoring', keywords: 'qr code tracking, qr code analytics, track qr scans, qr code statistics, free qr tracking, qr code monitoring',
alternates: { alternates: {
@ -23,6 +23,14 @@ export const metadata: Metadata = {
description: 'Track QR code scans with real-time analytics. Monitor location, device, time, and user behavior.', description: 'Track QR code scans with real-time analytics. Monitor location, device, time, and user behavior.',
url: 'https://www.qrmaster.net/qr-code-tracking', url: 'https://www.qrmaster.net/qr-code-tracking',
type: 'website', type: 'website',
images: [
{
url: 'https://www.qrmaster.net/og-image.png',
width: 1200,
height: 630,
alt: 'QR Code Tracking & Analytics - QR Master',
},
],
}, },
twitter: { twitter: {
title: 'QR Code Tracking & Analytics - Track Every Scan | QR Master', title: 'QR Code Tracking & Analytics - Track Every Scan | QR Master',

View File

@ -5,6 +5,7 @@ import { Bitcoin, Shield, Zap, Smartphone, Wallet, Coins, Sparkles, Download, Sh
import { QRCodeSVG } from 'qrcode.react'; import { QRCodeSVG } from 'qrcode.react';
import { ToolBreadcrumb } from '@/components/seo/BreadcrumbSchema'; import { ToolBreadcrumb } from '@/components/seo/BreadcrumbSchema';
import { RelatedTools } from '@/components/marketing/RelatedTools'; import { RelatedTools } from '@/components/marketing/RelatedTools';
import { generateSoftwareAppSchema, generateFaqSchema } from '@/lib/schema-utils';
// SEO Optimized Metadata // SEO Optimized Metadata
export const metadata: Metadata = { export const metadata: Metadata = {
@ -38,23 +39,12 @@ export const metadata: Metadata = {
const jsonLd = { const jsonLd = {
'@context': 'https://schema.org', '@context': 'https://schema.org',
'@graph': [ '@graph': [
{ generateSoftwareAppSchema(
'@type': 'SoftwareApplication', 'Crypto QR Code Generator',
name: 'Crypto QR Code Generator', 'Generate QR codes that contain your cryptocurrency wallet address for easy payments.',
applicationCategory: 'FinanceApplication', '/og-crypto-generator.png',
operatingSystem: 'Web Browser', 'FinanceApplication'
offers: { ),
'@type': 'Offer',
price: '0',
priceCurrency: 'USD',
},
aggregateRating: {
'@type': 'AggregateRating',
ratingValue: '4.9',
ratingCount: '870',
},
description: 'Generate QR codes that contain your cryptocurrency wallet address for easy payments.',
},
{ {
'@type': 'HowTo', '@type': 'HowTo',
name: 'How to Create a Crypto QR Code', name: 'How to Create a Crypto QR Code',
@ -93,51 +83,28 @@ const jsonLd = {
], ],
totalTime: 'PT30S', totalTime: 'PT30S',
}, },
{ generateFaqSchema({
'@type': 'FAQPage', 'Is it safe to share my wallet address?': {
mainEntity: [ question: 'Is it safe to share my wallet address?',
{ answer: 'Yes. Your public wallet address is designed to be shared so you can receive funds. Never share your private key.',
'@type': 'Question', },
name: 'Is it safe to share my wallet address?', 'Which currencies are supported?': {
acceptedAnswer: { question: 'Which currencies are supported?',
'@type': 'Answer', answer: 'Our generator supports standard URI schemes for Bitcoin, Ethereum, Solana, and can generally store any wallet string for other coins.',
text: 'Yes. Your public wallet address is designed to be shared so you can receive funds. Never share your private key.', },
}, 'Can I add a specific amount?': {
}, question: 'Can I add a specific amount?',
{ answer: 'Yes, you can pre-fill an amount so when the user scans, their wallet app automatically suggests the correct payment value.',
'@type': 'Question', },
name: 'Which currencies are supported?', 'Does it work with all wallets?': {
acceptedAnswer: { question: 'Does it work with all wallets?',
'@type': 'Answer', answer: 'Yes, standard crypto QR codes are universally readable by almost all modern wallet apps (Coinbase, MetaMask, Trust Wallet, etc.).',
text: 'Our generator supports standard URI schemes for Bitcoin, Ethereum, Solana, and can generally store any wallet string for other coins.', },
}, 'Are there any fees?': {
}, question: 'Are there any fees?',
{ answer: 'No. This generator is completely free. We do not charge any fees for generating codes or for the transactions made using them.',
'@type': 'Question', },
name: 'Can I add a specific amount?', }),
acceptedAnswer: {
'@type': 'Answer',
text: 'Yes, you can pre-fill an amount so when the user scans, their wallet app automatically suggests the correct payment value.',
},
},
{
'@type': 'Question',
name: 'Does it work with all wallets?',
acceptedAnswer: {
'@type': 'Answer',
text: 'Yes, standard crypto QR codes are universally readable by almost all modern wallet apps (Coinbase, MetaMask, Trust Wallet, etc.).',
},
},
{
'@type': 'Question',
name: 'Are there any fees?',
acceptedAnswer: {
'@type': 'Answer',
text: 'No. This generator is completely free. We do not charge any fees for generating codes or for the transactions made using them.',
},
},
],
},
], ],
}; };

View File

@ -5,6 +5,7 @@ import { Mail, Zap, Smartphone, Lock, Download, Sparkles } from 'lucide-react';
import { QRCodeSVG } from 'qrcode.react'; import { QRCodeSVG } from 'qrcode.react';
import { ToolBreadcrumb } from '@/components/seo/BreadcrumbSchema'; import { ToolBreadcrumb } from '@/components/seo/BreadcrumbSchema';
import { RelatedTools } from '@/components/marketing/RelatedTools'; import { RelatedTools } from '@/components/marketing/RelatedTools';
import { generateSoftwareAppSchema, generateFaqSchema } from '@/lib/schema-utils';
// SEO Optimized Metadata // SEO Optimized Metadata
export const metadata: Metadata = { export const metadata: Metadata = {
@ -29,14 +30,11 @@ export const metadata: Metadata = {
const jsonLd = { const jsonLd = {
'@context': 'https://schema.org', '@context': 'https://schema.org',
'@graph': [ '@graph': [
{ generateSoftwareAppSchema(
'@type': 'SoftwareApplication', 'Email QR Code Generator',
name: 'Email QR Code Generator', 'Generate Email QR codes for mailto links with subject and body.',
applicationCategory: 'UtilitiesApplication', '/og-email-generator.png'
operatingSystem: 'Web Browser', ),
offers: { '@type': 'Offer', price: '0', priceCurrency: 'USD' },
description: 'Generate Email QR codes for mailto links with subject and body.',
},
{ {
'@type': 'HowTo', '@type': 'HowTo',
name: 'How to Create an Email QR Code', name: 'How to Create an Email QR Code',
@ -49,36 +47,28 @@ const jsonLd = {
], ],
totalTime: 'PT30S', totalTime: 'PT30S',
}, },
{ generateFaqSchema({
'@type': 'FAQPage', 'How does it work?': {
mainEntity: [ question: 'How does it work?',
{ answer: 'When scanned, it opens the user\'s default email app (like Gmail or Outlook) with a new draft composed to your address.',
'@type': 'Question', },
name: 'How does it work?', 'Can I add a subject line?': {
acceptedAnswer: { '@type': 'Answer', text: 'When scanned, it opens the user\'s default email app (like Gmail or Outlook) with a new draft composed to your address.' } question: 'Can I add a subject line?',
}, answer: 'Yes! You can pre-fill the subject line and the body content so the sender just has to hit send.',
{ },
'@type': 'Question', 'Is it free?': {
name: 'Can I add a subject line?', question: 'Is it free?',
acceptedAnswer: { '@type': 'Answer', text: 'Yes! You can pre-fill the subject line and the body content so the sender just has to hit send.' } answer: 'Yes, 100% free with unlimited scans.',
}, },
{ 'Does it work with attachments?': {
'@type': 'Question', question: 'Does it work with attachments?',
name: 'Is it free?', answer: 'No. The standard mailto format does not support attaching files automatically. Users will have to attach files manually.',
acceptedAnswer: { '@type': 'Answer', text: 'Yes, 100% free with unlimited scans.' } },
}, 'Is it private?': {
{ question: 'Is it private?',
'@type': 'Question', answer: 'Yes. The data is encoded directly into the QR code. We do not store your email or message data.',
name: 'Does it work with attachments?', },
acceptedAnswer: { '@type': 'Answer', text: 'No. The standard mailto format does not support attaching files automatically. Users will have to attach files manually.' } }),
},
{
'@type': 'Question',
name: 'Is it private?',
acceptedAnswer: { '@type': 'Answer', text: 'Yes. The data is encoded directly into the QR code. We do not store your email or message data.' }
}
]
}
] ]
}; };

View File

@ -5,6 +5,7 @@ import { Calendar, Shield, Zap, Smartphone, Clock, UserCheck, Download, Share2,
import { QRCodeSVG } from 'qrcode.react'; import { QRCodeSVG } from 'qrcode.react';
import { ToolBreadcrumb } from '@/components/seo/BreadcrumbSchema'; import { ToolBreadcrumb } from '@/components/seo/BreadcrumbSchema';
import { RelatedTools } from '@/components/marketing/RelatedTools'; import { RelatedTools } from '@/components/marketing/RelatedTools';
import { generateSoftwareAppSchema, generateFaqSchema } from '@/lib/schema-utils';
// SEO Optimized Metadata // SEO Optimized Metadata
export const metadata: Metadata = { export const metadata: Metadata = {
@ -38,23 +39,11 @@ export const metadata: Metadata = {
const jsonLd = { const jsonLd = {
'@context': 'https://schema.org', '@context': 'https://schema.org',
'@graph': [ '@graph': [
{ generateSoftwareAppSchema(
'@type': 'SoftwareApplication', 'Event QR Code Generator',
name: 'Event QR Code Generator', 'Generate QR codes that add event details to the user\'s digital calendar.',
applicationCategory: 'UtilitiesApplication', '/og-event-generator.png'
operatingSystem: 'Web Browser', ),
offers: {
'@type': 'Offer',
price: '0',
priceCurrency: 'USD',
},
aggregateRating: {
'@type': 'AggregateRating',
ratingValue: '4.8',
ratingCount: '760',
},
description: 'Generate QR codes that add event details to the user\'s digital calendar.',
},
{ {
'@type': 'HowTo', '@type': 'HowTo',
name: 'How to Create an Event QR Code', name: 'How to Create an Event QR Code',
@ -93,51 +82,28 @@ const jsonLd = {
], ],
totalTime: 'PT45S', totalTime: 'PT45S',
}, },
{ generateFaqSchema({
'@type': 'FAQPage', 'Which calendars does it support?': {
mainEntity: [ question: 'Which calendars does it support?',
{ answer: 'The QR code uses the standard iCalendar (ICS) format. It works with Apple Calendar, Google Calendar, Outlook, and most other mobile calendar apps.',
'@type': 'Question', },
name: 'Which calendars does it support?', 'Can I change the date after printing?': {
acceptedAnswer: { question: 'Can I change the date after printing?',
'@type': 'Answer', answer: 'No. This is a static QR code, meaning the event details are permanently embedded in the image. If the date changes, you must create a new QR code. Use our Dynamic QR Code to edit events anytime.',
text: 'The QR code uses the standard iCalendar (ICS) format. It works with Apple Calendar, Google Calendar, Outlook, and most other mobile calendar apps.', },
}, 'Is there a limit to the description length?': {
}, question: 'Is there a limit to the description length?',
{ answer: 'Yes, because the data is stored in the QR code pattern. We recommend keeping descriptions concise (under 300 characters) to ensure the code remains easy to scan.',
'@type': 'Question', },
name: 'Can I change the date after printing?', 'Do users need an app?': {
acceptedAnswer: { question: 'Do users need an app?',
'@type': 'Answer', answer: 'No special app is needed. Standard camera apps on iOS and Android can read the code and will prompt the user to "Add to Calendar".',
text: 'No. This is a static QR code, meaning the event details are permanently embedded in the image. If the date changes, you must create a new QR code. Use our Dynamic QR Code to edit events anytime.', },
}, 'Is it free?': {
}, question: 'Is it free?',
{ answer: 'Yes. Creating and scanning the code is completely free and requires no signup.',
'@type': 'Question', },
name: 'Is there a limit to the description length?', }),
acceptedAnswer: {
'@type': 'Answer',
text: 'Yes, because the data is stored in the QR code pattern. We recommend keeping descriptions concise (under 300 characters) to ensure the code remains easy to scan.',
},
},
{
'@type': 'Question',
name: 'Do users need an app?',
acceptedAnswer: {
'@type': 'Answer',
text: 'No special app is needed. Standard camera apps on iOS and Android can read the code and will prompt the user to "Add to Calendar".',
},
},
{
'@type': 'Question',
name: 'Is it free?',
acceptedAnswer: {
'@type': 'Answer',
text: 'Yes. Creating and scanning the code is completely free and requires no signup.',
},
},
],
},
], ],
}; };

View File

@ -5,6 +5,7 @@ import { Facebook, Shield, Zap, Smartphone, ThumbsUp, Users, Download, Share2 }
import { QRCodeSVG } from 'qrcode.react'; import { QRCodeSVG } from 'qrcode.react';
import { ToolBreadcrumb } from '@/components/seo/BreadcrumbSchema'; import { ToolBreadcrumb } from '@/components/seo/BreadcrumbSchema';
import { RelatedTools } from '@/components/marketing/RelatedTools'; import { RelatedTools } from '@/components/marketing/RelatedTools';
import { generateSoftwareAppSchema, generateFaqSchema } from '@/lib/schema-utils';
// SEO Optimized Metadata // SEO Optimized Metadata
export const metadata: Metadata = { export const metadata: Metadata = {
@ -38,23 +39,11 @@ export const metadata: Metadata = {
const jsonLd = { const jsonLd = {
'@context': 'https://schema.org', '@context': 'https://schema.org',
'@graph': [ '@graph': [
{ generateSoftwareAppSchema(
'@type': 'SoftwareApplication', 'Facebook QR Code Generator',
name: 'Facebook QR Code Generator', 'Generate QR codes that direct users to a Facebook page, profile, or post.',
applicationCategory: 'UtilitiesApplication', '/og-facebook-generator.png'
operatingSystem: 'Web Browser', ),
offers: {
'@type': 'Offer',
price: '0',
priceCurrency: 'USD',
},
aggregateRating: {
'@type': 'AggregateRating',
ratingValue: '4.8',
ratingCount: '1120',
},
description: 'Generate QR codes that direct users to a Facebook page, profile, or post.',
},
{ {
'@type': 'HowTo', '@type': 'HowTo',
name: 'How to Create a Facebook QR Code', name: 'How to Create a Facebook QR Code',
@ -93,51 +82,28 @@ const jsonLd = {
], ],
totalTime: 'PT30S', totalTime: 'PT30S',
}, },
{ generateFaqSchema({
'@type': 'FAQPage', 'Does it open the Facebook app?': {
mainEntity: [ question: 'Does it open the Facebook app?',
{ answer: 'Yes! On most mobile devices, standard Facebook links are automatically detected and opened in the Facebook app if it is installed.',
'@type': 'Question', },
name: 'Does it open the Facebook app?', 'Can I link to a specific post?': {
acceptedAnswer: { question: 'Can I link to a specific post?',
'@type': 'Answer', answer: 'Absolutely. Just paste the direct link to the post (click the timestamp on the post to get the link).',
text: 'Yes! On most mobile devices, standard Facebook links are automatically detected and opened in the Facebook app if it is installed.', },
}, 'Does it work for Facebook Events?': {
}, question: 'Does it work for Facebook Events?',
{ answer: 'Yes. Simply copy the full URL of your Facebook Event and paste it into the generator.',
'@type': 'Question', },
name: 'Can I link to a specific post?', 'Is it free?': {
acceptedAnswer: { question: 'Is it free?',
'@type': 'Answer', answer: 'Yes, this generator is 100% free to use for personal or business purposes.',
text: 'Absolutely. Just paste the direct link to the post (click the timestamp on the post to get the link).', },
}, 'Can I track scans?': {
}, question: 'Can I track scans?',
{ answer: 'This static QR code does not include analytics. To track how many people scan your code, you should use our Dynamic QR Code service.',
'@type': 'Question', },
name: 'Does it work for Facebook Events?', }),
acceptedAnswer: {
'@type': 'Answer',
text: 'Yes. Simply copy the full URL of your Facebook Event and paste it into the generator.',
},
},
{
'@type': 'Question',
name: 'Is it free?',
acceptedAnswer: {
'@type': 'Answer',
text: 'Yes, this generator is 100% free to use for personal or business purposes.',
},
},
{
'@type': 'Question',
name: 'Can I track scans?',
acceptedAnswer: {
'@type': 'Answer',
text: 'This static QR code does not include analytics. To track how many people scan your code, you should use our Dynamic QR Code service.',
},
},
],
},
], ],
}; };

View File

@ -5,6 +5,7 @@ import { MapPin, Shield, Zap, Smartphone, Navigation, Map, Download, Share2 } fr
import { QRCodeSVG } from 'qrcode.react'; import { QRCodeSVG } from 'qrcode.react';
import { ToolBreadcrumb } from '@/components/seo/BreadcrumbSchema'; import { ToolBreadcrumb } from '@/components/seo/BreadcrumbSchema';
import { RelatedTools } from '@/components/marketing/RelatedTools'; import { RelatedTools } from '@/components/marketing/RelatedTools';
import { generateSoftwareAppSchema, generateFaqSchema } from '@/lib/schema-utils';
// SEO Optimized Metadata // SEO Optimized Metadata
export const metadata: Metadata = { export const metadata: Metadata = {
@ -38,23 +39,11 @@ export const metadata: Metadata = {
const jsonLd = { const jsonLd = {
'@context': 'https://schema.org', '@context': 'https://schema.org',
'@graph': [ '@graph': [
{ generateSoftwareAppSchema(
'@type': 'SoftwareApplication', 'Geolocation QR Code Generator',
name: 'Geolocation QR Code Generator', 'Generate QR codes that open specific geographic coordinates in map applications.',
applicationCategory: 'UtilitiesApplication', '/og-geolocation-generator.png'
operatingSystem: 'Web Browser', ),
offers: {
'@type': 'Offer',
price: '0',
priceCurrency: 'USD',
},
aggregateRating: {
'@type': 'AggregateRating',
ratingValue: '4.7',
ratingCount: '890',
},
description: 'Generate QR codes that open specific geographic coordinates in map applications.',
},
{ {
'@type': 'HowTo', '@type': 'HowTo',
name: 'How to Create a Location QR Code', name: 'How to Create a Location QR Code',
@ -93,51 +82,28 @@ const jsonLd = {
], ],
totalTime: 'PT45S', totalTime: 'PT45S',
}, },
{ generateFaqSchema({
'@type': 'FAQPage', 'Which map app does it open?': {
mainEntity: [ question: 'Which map app does it open?',
{ answer: 'Our generator creates a universal Google Maps link. On most devices, this will open the Google Maps app if installed, or the browser version if not. It is the most compatible method.',
'@type': 'Question', },
name: 'Which map app does it open?', 'How do I find my Latitude and Longitude?': {
acceptedAnswer: { question: 'How do I find my Latitude and Longitude?',
'@type': 'Answer', answer: 'On Google Maps desktop: Right-click any spot on the map. The first item in the menu is the coordinates. Click to copy them.',
text: 'Our generator creates a universal Google Maps link. On most devices, this will open the Google Maps app if installed, or the browser version if not. It is the most compatible method.', },
}, 'Does it work offline?': {
}, question: 'Does it work offline?',
{ answer: 'The QR code itself can be scanned offline, but the user will likely need an internet connection to load the map and get directions.',
'@type': 'Question', },
name: 'How do I find my Latitude and Longitude?', 'Can I use an address instead?': {
acceptedAnswer: { question: 'Can I use an address instead?',
'@type': 'Answer', answer: 'For precise results, we use coordinates. However, you can use our URL Generator and paste a link to your Google Maps address search result if you prefer.',
text: 'On Google Maps desktop: Right-click any spot on the map. The first item in the menu is the coordinates. Click to copy them.', },
}, 'Is it free?': {
}, question: 'Is it free?',
{ answer: 'Yes, generating this location QR code is completely free and requires no signup.',
'@type': 'Question', },
name: 'Does it work offline?', }),
acceptedAnswer: {
'@type': 'Answer',
text: 'The QR code itself can be scanned offline, but the user will likely need an internet connection to load the map and get directions.',
},
},
{
'@type': 'Question',
name: 'Can I use an address instead?',
acceptedAnswer: {
'@type': 'Answer',
text: 'For precise results, we use coordinates. However, you can use our URL Generator and paste a link to your Google Maps address search result if you prefer.',
},
},
{
'@type': 'Question',
name: 'Is it free?',
acceptedAnswer: {
'@type': 'Answer',
text: 'Yes, generating this location QR code is completely free and requires no signup.',
},
},
],
},
], ],
}; };

View File

@ -5,6 +5,7 @@ import { Instagram, Shield, Zap, Smartphone, Camera, Heart, Download, Share2 } f
import { QRCodeSVG } from 'qrcode.react'; import { QRCodeSVG } from 'qrcode.react';
import { ToolBreadcrumb } from '@/components/seo/BreadcrumbSchema'; import { ToolBreadcrumb } from '@/components/seo/BreadcrumbSchema';
import { RelatedTools } from '@/components/marketing/RelatedTools'; import { RelatedTools } from '@/components/marketing/RelatedTools';
import { generateSoftwareAppSchema, generateFaqSchema } from '@/lib/schema-utils';
// SEO Optimized Metadata // SEO Optimized Metadata
export const metadata: Metadata = { export const metadata: Metadata = {
@ -38,23 +39,11 @@ export const metadata: Metadata = {
const jsonLd = { const jsonLd = {
'@context': 'https://schema.org', '@context': 'https://schema.org',
'@graph': [ '@graph': [
{ generateSoftwareAppSchema(
'@type': 'SoftwareApplication', 'Instagram QR Code Generator',
name: 'Instagram QR Code Generator', 'Generate QR codes that direct users to an Instagram profile or post.',
applicationCategory: 'UtilitiesApplication', '/og-instagram-generator.png'
operatingSystem: 'Web Browser', ),
offers: {
'@type': 'Offer',
price: '0',
priceCurrency: 'USD',
},
aggregateRating: {
'@type': 'AggregateRating',
ratingValue: '4.9',
ratingCount: '2150',
},
description: 'Generate QR codes that direct users to an Instagram profile or post.',
},
{ {
'@type': 'HowTo', '@type': 'HowTo',
name: 'How to Create an Instagram QR Code', name: 'How to Create an Instagram QR Code',
@ -93,51 +82,28 @@ const jsonLd = {
], ],
totalTime: 'PT30S', totalTime: 'PT30S',
}, },
{ generateFaqSchema({
'@type': 'FAQPage', 'Is this an Instagram Nametag?': {
mainEntity: [ question: 'Is this an Instagram Nametag?',
{ answer: 'It works similarly! While Instagram has its own internal "Nametag" or "QR Code" feature, our generator allows you to create a standard QR code that is more customizable and can be tracked with our Dynamic plans.',
'@type': 'Question', },
name: 'Is this an Instagram Nametag?', 'Does it open the Instagram app?': {
acceptedAnswer: { question: 'Does it open the Instagram app?',
'@type': 'Answer', answer: 'Yes. When scanned on a mobile device with Instagram installed, it will deep-link directly to the profile in the app.',
text: 'It works similarly! While Instagram has its own internal "Nametag" or "QR Code" feature, our generator allows you to create a standard QR code that is more customizable and can be tracked with our Dynamic plans.', },
}, 'Can I link to a specific photo or reel?': {
}, question: 'Can I link to a specific photo or reel?',
{ answer: 'Yes! Instead of your username, just paste the full link to the specific post or reel.',
'@type': 'Question', },
name: 'Does it open the Instagram app?', 'Is it free?': {
acceptedAnswer: { question: 'Is it free?',
'@type': 'Answer', answer: 'Yes, generating this QR code is 100% free.',
text: 'Yes. When scanned on a mobile device with Instagram installed, it will deep-link directly to the profile in the app.', },
}, 'Can I track scans?': {
}, question: 'Can I track scans?',
{ answer: 'Not with this static tool. If you need scan analytics, consider using our Dynamic QR Code solution.',
'@type': 'Question', },
name: 'Can I link to a specific photo or reel?', }),
acceptedAnswer: {
'@type': 'Answer',
text: 'Yes! Instead of your username, just paste the full link to the specific post or reel.',
},
},
{
'@type': 'Question',
name: 'Is it free?',
acceptedAnswer: {
'@type': 'Answer',
text: 'Yes, generating this QR code is 100% free.',
},
},
{
'@type': 'Question',
name: 'Can I track scans?',
acceptedAnswer: {
'@type': 'Answer',
text: 'Not with this static tool. If you need scan analytics, consider using our Dynamic QR Code solution.',
},
},
],
},
], ],
}; };

View File

@ -5,6 +5,7 @@ import { CreditCard, Shield, Zap, Smartphone, DollarSign, Download, Share2, Bank
import { QRCodeSVG } from 'qrcode.react'; import { QRCodeSVG } from 'qrcode.react';
import { ToolBreadcrumb } from '@/components/seo/BreadcrumbSchema'; import { ToolBreadcrumb } from '@/components/seo/BreadcrumbSchema';
import { RelatedTools } from '@/components/marketing/RelatedTools'; import { RelatedTools } from '@/components/marketing/RelatedTools';
import { generateSoftwareAppSchema, generateFaqSchema } from '@/lib/schema-utils';
// SEO Optimized Metadata // SEO Optimized Metadata
export const metadata: Metadata = { export const metadata: Metadata = {
@ -38,23 +39,12 @@ export const metadata: Metadata = {
const jsonLd = { const jsonLd = {
'@context': 'https://schema.org', '@context': 'https://schema.org',
'@graph': [ '@graph': [
{ generateSoftwareAppSchema(
'@type': 'SoftwareApplication', 'PayPal QR Code Generator',
name: 'PayPal QR Code Generator', 'Generate QR codes that link to your PayPal.me page for instant payments.',
applicationCategory: 'FinanceApplication', '/og-paypal-generator.png',
operatingSystem: 'Web Browser', 'FinanceApplication'
offers: { ),
'@type': 'Offer',
price: '0',
priceCurrency: 'USD',
},
aggregateRating: {
'@type': 'AggregateRating',
ratingValue: '4.9',
ratingCount: '980',
},
description: 'Generate QR codes that link to your PayPal.me page for instant payments.',
},
{ {
'@type': 'HowTo', '@type': 'HowTo',
name: 'How to Create a PayPal QR Code', name: 'How to Create a PayPal QR Code',
@ -93,51 +83,28 @@ const jsonLd = {
], ],
totalTime: 'PT30S', totalTime: 'PT30S',
}, },
{ generateFaqSchema({
'@type': 'FAQPage', 'How does the PayPal QR code work?': {
mainEntity: [ question: 'How does the PayPal QR code work?',
{ answer: 'When scanned, it opens the PayPal app or website with your PayPal.me link. If you set an amount, it will be pre-filled for the payer.',
'@type': 'Question', },
name: 'How does the PayPal QR code work?', 'Do I need a PayPal Business account?': {
acceptedAnswer: { question: 'Do I need a PayPal Business account?',
'@type': 'Answer', answer: 'No. Any PayPal account with a PayPal.me link can use this generator. Personal accounts work fine for tips and donations.',
text: 'When scanned, it opens the PayPal app or website with your PayPal.me link. If you set an amount, it will be pre-filled for the payer.', },
}, 'Is there a fee for using the QR code?': {
}, question: 'Is there a fee for using the QR code?',
{ answer: 'This generator is 100% free. PayPal may charge their standard transaction fees when you receive payments.',
'@type': 'Question', },
name: 'Do I need a PayPal Business account?', 'Can I change the amount later?': {
acceptedAnswer: { question: 'Can I change the amount later?',
'@type': 'Answer', answer: 'No, this is a static QR code. The amount is encoded permanently. For variable amounts, leave the amount field empty.',
text: 'No. Any PayPal account with a PayPal.me link can use this generator. Personal accounts work fine for tips and donations.', },
}, 'What currencies are supported?': {
}, question: 'What currencies are supported?',
{ answer: 'We support EUR, USD, GBP, and CHF. PayPal handles currency conversion automatically.',
'@type': 'Question', },
name: 'Is there a fee for using the QR code?', }),
acceptedAnswer: {
'@type': 'Answer',
text: 'This generator is 100% free. PayPal may charge their standard transaction fees when you receive payments.',
},
},
{
'@type': 'Question',
name: 'Can I change the amount later?',
acceptedAnswer: {
'@type': 'Answer',
text: 'No, this is a static QR code. The amount is encoded permanently. For variable amounts, leave the amount field empty.',
},
},
{
'@type': 'Question',
name: 'What currencies are supported?',
acceptedAnswer: {
'@type': 'Answer',
text: 'We support EUR, USD, GBP, and CHF. PayPal handles currency conversion automatically.',
},
},
],
},
], ],
}; };

View File

@ -5,6 +5,7 @@ import { Phone, Shield, Zap, Smartphone, PhoneCall, Download } from 'lucide-reac
import { QRCodeSVG } from 'qrcode.react'; import { QRCodeSVG } from 'qrcode.react';
import { ToolBreadcrumb } from '@/components/seo/BreadcrumbSchema'; import { ToolBreadcrumb } from '@/components/seo/BreadcrumbSchema';
import { RelatedTools } from '@/components/marketing/RelatedTools'; import { RelatedTools } from '@/components/marketing/RelatedTools';
import { generateSoftwareAppSchema, generateFaqSchema } from '@/lib/schema-utils';
// SEO Optimized Metadata // SEO Optimized Metadata
export const metadata: Metadata = { export const metadata: Metadata = {
@ -38,23 +39,11 @@ export const metadata: Metadata = {
const jsonLd = { const jsonLd = {
'@context': 'https://schema.org', '@context': 'https://schema.org',
'@graph': [ '@graph': [
{ generateSoftwareAppSchema(
'@type': 'SoftwareApplication', 'Phone QR Code Generator',
name: 'Phone QR Code Generator', 'Generate QR codes that trigger a phone call when scanned on a mobile device.',
applicationCategory: 'UtilitiesApplication', '/og-phone-generator.png'
operatingSystem: 'Web Browser', ),
offers: {
'@type': 'Offer',
price: '0',
priceCurrency: 'USD',
},
aggregateRating: {
'@type': 'AggregateRating',
ratingValue: '4.8',
ratingCount: '1500',
},
description: 'Generate QR codes that trigger a phone call when scanned on a mobile device.',
},
{ {
'@type': 'HowTo', '@type': 'HowTo',
name: 'How to Create a Phone QR Code', name: 'How to Create a Phone QR Code',
@ -93,51 +82,28 @@ const jsonLd = {
], ],
totalTime: 'PT30S', totalTime: 'PT30S',
}, },
{ generateFaqSchema({
'@type': 'FAQPage', 'Does it call automatically?': {
mainEntity: [ question: 'Does it call automatically?',
{ answer: 'Scanning the QR code opens the phone dialer with the number pre-filled. The user must tap the call button to initiate the call.',
'@type': 'Question', },
name: 'Does it call automatically?', 'Does it work internationally?': {
acceptedAnswer: { question: 'Does it work internationally?',
'@type': 'Answer', answer: 'Yes! We recommend entering your number in international format (starting with +) to ensure it works anywhere in the world.',
text: 'Scanning the QR code opens the phone dialer with the number pre-filled. The user must tap the call button to initiate the call.', },
}, 'Is my phone number private?': {
}, question: 'Is my phone number private?',
{ answer: 'Yes. We do not store your number. It is encoded directly into the QR code image.',
'@type': 'Question', },
name: 'Does it work internationally?', 'Can I track calls?': {
acceptedAnswer: { question: 'Can I track calls?',
'@type': 'Answer', answer: 'This static QR code cannot track calls. For tracking scans and analytics, consider using our Dynamic QR Code solution.',
text: 'Yes! We recommend entering your number in international format (starting with +) to ensure it works anywhere in the world.', },
}, 'Is it free?': {
}, question: 'Is it free?',
{ answer: 'Yes, completely free. We do not charge for generating or scanning the code.',
'@type': 'Question', },
name: 'Is my phone number private?', }),
acceptedAnswer: {
'@type': 'Answer',
text: 'Yes. We do not store your number. It is encoded directly into the QR code image.',
},
},
{
'@type': 'Question',
name: 'Can I track calls?',
acceptedAnswer: {
'@type': 'Answer',
text: 'This static QR code cannot track calls. For tracking scans and analytics, consider using our Dynamic QR Code solution.',
},
},
{
'@type': 'Question',
name: 'Is it free?',
acceptedAnswer: {
'@type': 'Answer',
text: 'Yes, completely free. We do not charge for generating or scanning the code.',
},
},
],
},
], ],
}; };

View File

@ -5,6 +5,7 @@ import { MessageSquare, Shield, Zap, Smartphone, Send } from 'lucide-react';
import { QRCodeSVG } from 'qrcode.react'; import { QRCodeSVG } from 'qrcode.react';
import { ToolBreadcrumb } from '@/components/seo/BreadcrumbSchema'; import { ToolBreadcrumb } from '@/components/seo/BreadcrumbSchema';
import { RelatedTools } from '@/components/marketing/RelatedTools'; import { RelatedTools } from '@/components/marketing/RelatedTools';
import { generateSoftwareAppSchema, generateFaqSchema } from '@/lib/schema-utils';
// SEO Optimized Metadata // SEO Optimized Metadata
export const metadata: Metadata = { export const metadata: Metadata = {
@ -38,23 +39,11 @@ export const metadata: Metadata = {
const jsonLd = { const jsonLd = {
'@context': 'https://schema.org', '@context': 'https://schema.org',
'@graph': [ '@graph': [
{ generateSoftwareAppSchema(
'@type': 'SoftwareApplication', 'SMS QR Code Generator',
name: 'SMS QR Code Generator', 'Generate QR codes that open the user\'s SMS app with a pre-filled message.',
applicationCategory: 'UtilitiesApplication', '/og-sms-generator.png'
operatingSystem: 'Web Browser', ),
offers: {
'@type': 'Offer',
price: '0',
priceCurrency: 'USD',
},
aggregateRating: {
'@type': 'AggregateRating',
ratingValue: '4.8',
ratingCount: '1350',
},
description: 'Generate QR codes that open the user\'s SMS app with a pre-filled message.',
},
{ {
'@type': 'HowTo', '@type': 'HowTo',
name: 'How to Create an SMS QR Code', name: 'How to Create an SMS QR Code',
@ -81,43 +70,24 @@ const jsonLd = {
], ],
totalTime: 'PT30S', totalTime: 'PT30S',
}, },
{ generateFaqSchema({
'@type': 'FAQPage', 'Does the text send automatically?': {
mainEntity: [ question: 'Does the text send automatically?',
{ answer: 'No. The QR code opens the messaging app with the text typed out. The user must simply tap "Send". This is a security feature of all smartphones.',
'@type': 'Question', },
name: 'Does the text send automatically?', 'Is there a cost?': {
acceptedAnswer: { question: 'Is there a cost?',
'@type': 'Answer', answer: 'Generating the code is free. Standard SMS rates apply for the person sending the text message, depending on their carrier plan.',
text: 'No. The QR code opens the messaging app with the text typed out. The user must simply tap "Send". This is a security feature of all smartphones.', },
}, 'Can I change the message later?': {
}, question: 'Can I change the message later?',
{ answer: 'No. Static QR codes have the message embedded in them. To change the message, you need a new QR code.',
'@type': 'Question', },
name: 'Is there a cost?', 'What uses are there for SMS QR codes?': {
acceptedAnswer: { question: 'What uses are there for SMS QR codes?',
'@type': 'Answer', answer: 'They are great for SMS marketing opt-ins ("Text JOIN to 12345"), customer support requests, or voting via text.',
text: 'Generating the code is free. Standard SMS rates apply for the person sending the text message, depending on their carrier plan.', },
}, }),
},
{
'@type': 'Question',
name: 'Can I change the message later?',
acceptedAnswer: {
'@type': 'Answer',
text: 'No. Static QR codes have the message embedded in them. To change the message, you need a new QR code.',
},
},
{
'@type': 'Question',
name: 'What uses are there for SMS QR codes?',
acceptedAnswer: {
'@type': 'Answer',
text: 'They are great for SMS marketing opt-ins ("Text JOIN to 12345"), customer support requests, or voting via text.',
},
},
],
},
], ],
}; };

View File

@ -5,6 +5,7 @@ import { Users, Shield, Zap, Video, MessageCircle, Download, Share2 } from 'luci
import { QRCodeSVG } from 'qrcode.react'; import { QRCodeSVG } from 'qrcode.react';
import { ToolBreadcrumb } from '@/components/seo/BreadcrumbSchema'; import { ToolBreadcrumb } from '@/components/seo/BreadcrumbSchema';
import { RelatedTools } from '@/components/marketing/RelatedTools'; import { RelatedTools } from '@/components/marketing/RelatedTools';
import { generateSoftwareAppSchema, generateFaqSchema } from '@/lib/schema-utils';
// SEO Optimized Metadata // SEO Optimized Metadata
export const metadata: Metadata = { export const metadata: Metadata = {
@ -38,23 +39,12 @@ export const metadata: Metadata = {
const jsonLd = { const jsonLd = {
'@context': 'https://schema.org', '@context': 'https://schema.org',
'@graph': [ '@graph': [
{ generateSoftwareAppSchema(
'@type': 'SoftwareApplication', 'Microsoft Teams QR Code Generator',
name: 'Microsoft Teams QR Code Generator', 'Generate QR codes that let people join your Microsoft Teams meeting with one scan.',
applicationCategory: 'BusinessApplication', '/og-teams-generator.png',
operatingSystem: 'Web Browser', 'BusinessApplication'
offers: { ),
'@type': 'Offer',
price: '0',
priceCurrency: 'USD',
},
aggregateRating: {
'@type': 'AggregateRating',
ratingValue: '4.9',
ratingCount: '890',
},
description: 'Generate QR codes that let people join your Microsoft Teams meeting with one scan.',
},
{ {
'@type': 'HowTo', '@type': 'HowTo',
name: 'How to Create a Microsoft Teams QR Code', name: 'How to Create a Microsoft Teams QR Code',
@ -87,43 +77,24 @@ const jsonLd = {
], ],
totalTime: 'PT30S', totalTime: 'PT30S',
}, },
{ generateFaqSchema({
'@type': 'FAQPage', 'What happens when someone scans the QR code?': {
mainEntity: [ question: 'What happens when someone scans the QR code?',
{ answer: 'Microsoft Teams opens and the user is prompted to join the meeting. Works on desktop, mobile, and web.',
'@type': 'Question', },
name: 'What happens when someone scans the QR code?', 'Does it work for recurring meetings?': {
acceptedAnswer: { question: 'Does it work for recurring meetings?',
'@type': 'Answer', answer: 'Yes! If your recurring meeting uses the same meeting link, the QR code will work for all sessions.',
text: 'Microsoft Teams opens and the user is prompted to join the meeting. Works on desktop, mobile, and web.', },
}, 'Can guests without Teams accounts join?': {
}, question: 'Can guests without Teams accounts join?',
{ answer: 'Yes. Guests can join Teams meetings via the web browser without needing a Microsoft account.',
'@type': 'Question', },
name: 'Does it work for recurring meetings?', 'Is this for personal or business Teams?': {
acceptedAnswer: { question: 'Is this for personal or business Teams?',
'@type': 'Answer', answer: 'Both! Works with Microsoft Teams for work, school, and personal accounts.',
text: 'Yes! If your recurring meeting uses the same meeting link, the QR code will work for all sessions.', },
}, }),
},
{
'@type': 'Question',
name: 'Can guests without Teams accounts join?',
acceptedAnswer: {
'@type': 'Answer',
text: 'Yes. Guests can join Teams meetings via the web browser without needing a Microsoft account.',
},
},
{
'@type': 'Question',
name: 'Is this for personal or business Teams?',
acceptedAnswer: {
'@type': 'Answer',
text: 'Both! Works with Microsoft Teams for work, school, and personal accounts.',
},
},
],
},
], ],
}; };

View File

@ -5,6 +5,7 @@ import { Type, Shield, Zap, Smartphone, FileText, QrCode, Download, Share2 } fro
import { QRCodeSVG } from 'qrcode.react'; import { QRCodeSVG } from 'qrcode.react';
import { ToolBreadcrumb } from '@/components/seo/BreadcrumbSchema'; import { ToolBreadcrumb } from '@/components/seo/BreadcrumbSchema';
import { RelatedTools } from '@/components/marketing/RelatedTools'; import { RelatedTools } from '@/components/marketing/RelatedTools';
import { generateSoftwareAppSchema, generateFaqSchema } from '@/lib/schema-utils';
// SEO Optimized Metadata // SEO Optimized Metadata
export const metadata: Metadata = { export const metadata: Metadata = {
@ -38,23 +39,11 @@ export const metadata: Metadata = {
const jsonLd = { const jsonLd = {
'@context': 'https://schema.org', '@context': 'https://schema.org',
'@graph': [ '@graph': [
{ generateSoftwareAppSchema(
'@type': 'SoftwareApplication', 'Text QR Code Generator',
name: 'Text QR Code Generator', 'Generate QR codes for plain text messages. Works offline once generated. No data collection.',
applicationCategory: 'UtilitiesApplication', '/og-text-generator.png'
operatingSystem: 'Web Browser', ),
offers: {
'@type': 'Offer',
price: '0',
priceCurrency: 'USD',
},
aggregateRating: {
'@type': 'AggregateRating',
ratingValue: '4.8',
ratingCount: '1240',
},
description: 'Generate QR codes for plain text messages. Works offline once generated. No data collection.',
},
{ {
'@type': 'HowTo', '@type': 'HowTo',
name: 'How to Create a Text QR Code', name: 'How to Create a Text QR Code',
@ -93,51 +82,28 @@ const jsonLd = {
], ],
totalTime: 'PT30S', totalTime: 'PT30S',
}, },
{ generateFaqSchema({
'@type': 'FAQPage', 'Is there a character limit?': {
mainEntity: [ question: 'Is there a character limit?',
{ answer: 'Yes, we recommend keeping it under 300 characters for optimal scanning. While QR codes can hold more, more text makes the code denser and harder to scan.',
'@type': 'Question', },
name: 'Is there a character limit?', 'Do I need internet to scan a Text QR code?': {
acceptedAnswer: { question: 'Do I need internet to scan a Text QR code?',
'@type': 'Answer', answer: 'No. Text QR codes work completely offline. The text content is embedded directly into the QR code pattern.',
text: 'Yes, we recommend keeping it under 300 characters for optimal scanning. While QR codes can hold more, more text makes the code denser and harder to scan.', },
}, 'Is my text private?': {
}, question: 'Is my text private?',
{ answer: 'Yes. This generator runs 100% in your browser. We do not store or see the text you type.',
'@type': 'Question', },
name: 'Do I need internet to scan a Text QR code?', 'How do I scan a text QR code?': {
acceptedAnswer: { question: 'How do I scan a text QR code?',
'@type': 'Answer', answer: 'Open your phone camera or a QR scanner app and point it at the code. The text will appear on your screen automatically.',
text: 'No. Text QR codes work completely offline. The text content is embedded directly into the QR code pattern.', },
}, 'Can I edit the text later?': {
}, question: 'Can I edit the text later?',
{ answer: 'No, this is a static QR code. The text is permanent. If you need to change it, you must create a new QR code.',
'@type': 'Question', },
name: 'Is my text private?', }),
acceptedAnswer: {
'@type': 'Answer',
text: 'Yes. This generator runs 100% in your browser. We do not store or see the text you type.',
},
},
{
'@type': 'Question',
name: 'How do I scan a text QR code?',
acceptedAnswer: {
'@type': 'Answer',
text: 'Open your phone camera or a QR scanner app and point it at the code. The text will appear on your screen automatically.',
},
},
{
'@type': 'Question',
name: 'Can I edit the text later?',
acceptedAnswer: {
'@type': 'Answer',
text: 'No, this is a static QR code. The text is permanent. If you need to change it, you must create a new QR code.',
},
},
],
},
], ],
}; };

View File

@ -5,6 +5,7 @@ import { Music, Shield, Zap, Smartphone, Video, Heart, Download, Share2 } from '
import { QRCodeSVG } from 'qrcode.react'; import { QRCodeSVG } from 'qrcode.react';
import { ToolBreadcrumb } from '@/components/seo/BreadcrumbSchema'; import { ToolBreadcrumb } from '@/components/seo/BreadcrumbSchema';
import { RelatedTools } from '@/components/marketing/RelatedTools'; import { RelatedTools } from '@/components/marketing/RelatedTools';
import { generateSoftwareAppSchema, generateFaqSchema } from '@/lib/schema-utils';
// SEO Optimized Metadata // SEO Optimized Metadata
export const metadata: Metadata = { export const metadata: Metadata = {
@ -38,23 +39,11 @@ export const metadata: Metadata = {
const jsonLd = { const jsonLd = {
'@context': 'https://schema.org', '@context': 'https://schema.org',
'@graph': [ '@graph': [
{ generateSoftwareAppSchema(
'@type': 'SoftwareApplication', 'TikTok QR Code Generator',
name: 'TikTok QR Code Generator', 'Generate QR codes that direct users to a TikTok profile.',
applicationCategory: 'UtilitiesApplication', '/og-tiktok-generator.png'
operatingSystem: 'Web Browser', ),
offers: {
'@type': 'Offer',
price: '0',
priceCurrency: 'USD',
},
aggregateRating: {
'@type': 'AggregateRating',
ratingValue: '4.9',
ratingCount: '1560',
},
description: 'Generate QR codes that direct users to a TikTok profile.',
},
{ {
'@type': 'HowTo', '@type': 'HowTo',
name: 'How to Create a TikTok QR Code', name: 'How to Create a TikTok QR Code',
@ -93,51 +82,28 @@ const jsonLd = {
], ],
totalTime: 'PT30S', totalTime: 'PT30S',
}, },
{ generateFaqSchema({
'@type': 'FAQPage', 'Does this replace the in-app QR code?': {
mainEntity: [ question: 'Does this replace the in-app QR code?',
{ answer: 'You can use either! The advantage of our generator is that you can print high-resolution versions for large posters, customize the color/frame, and it works with any standard QR scanner.',
'@type': 'Question', },
name: 'Does it open the TikTok app?', 'Can I link to a specific video?': {
acceptedAnswer: { question: 'Can I link to a specific video?',
'@type': 'Answer', answer: 'Yes, just paste the full video URL (e.g. tiktok.com/@user/video/123...) instead of your username.',
text: 'Yes! If the app is installed, the QR code will deep-link directly to your profile in the TikTok app.', },
}, 'Is it free?': {
}, question: 'Is it free?',
{ answer: 'Yes, completely free from start to finish.',
'@type': 'Question', },
name: 'What is a TikCode?', 'Can I track who scanned my code?': {
acceptedAnswer: { question: 'Can I track who scanned my code?',
'@type': 'Answer', answer: 'No, this is a static QR code. For analytics, you need a Dynamic QR Code.',
text: 'TikCode was TikTok\'s proprietary QR code system. They have moved towards standard QR codes, which is what our tool generates. These are more compatible with standard camera apps.', },
}, 'Is it safe?': {
}, question: 'Is it safe?',
{ answer: 'Yes. The QR code simply contains a link to your TikTok profile. No personal data is collected.',
'@type': 'Question', },
name: 'Is it free?', }),
acceptedAnswer: {
'@type': 'Answer',
text: 'Yes, this generator is completely free.',
},
},
{
'@type': 'Question',
name: 'Can I track who scanned my code?',
acceptedAnswer: {
'@type': 'Answer',
text: 'No, this is a static QR code. For analytics, you need a Dynamic QR Code.',
},
},
{
'@type': 'Question',
name: 'Is it safe?',
acceptedAnswer: {
'@type': 'Answer',
text: 'Yes. The QR code simply contains a link to your TikTok profile. No personal data is collected.',
},
},
],
},
], ],
}; };

View File

@ -5,6 +5,7 @@ import { Twitter, Shield, Zap, Smartphone, MessageCircle, UserPlus, Download, Sh
import { QRCodeSVG } from 'qrcode.react'; import { QRCodeSVG } from 'qrcode.react';
import { ToolBreadcrumb } from '@/components/seo/BreadcrumbSchema'; import { ToolBreadcrumb } from '@/components/seo/BreadcrumbSchema';
import { RelatedTools } from '@/components/marketing/RelatedTools'; import { RelatedTools } from '@/components/marketing/RelatedTools';
import { generateSoftwareAppSchema, generateFaqSchema } from '@/lib/schema-utils';
// SEO Optimized Metadata // SEO Optimized Metadata
export const metadata: Metadata = { export const metadata: Metadata = {
@ -38,23 +39,11 @@ export const metadata: Metadata = {
const jsonLd = { const jsonLd = {
'@context': 'https://schema.org', '@context': 'https://schema.org',
'@graph': [ '@graph': [
{ generateSoftwareAppSchema(
'@type': 'SoftwareApplication', 'Twitter (X) QR Code Generator',
name: 'Twitter (X) QR Code Generator', 'Generate QR codes that direct users to an X (Twitter) profile or tweet.',
applicationCategory: 'UtilitiesApplication', '/og-twitter-generator.png'
operatingSystem: 'Web Browser', ),
offers: {
'@type': 'Offer',
price: '0',
priceCurrency: 'USD',
},
aggregateRating: {
'@type': 'AggregateRating',
ratingValue: '4.8',
ratingCount: '980',
},
description: 'Generate QR codes that direct users to an X (Twitter) profile or tweet.',
},
{ {
'@type': 'HowTo', '@type': 'HowTo',
name: 'How to Create a Twitter QR Code', name: 'How to Create a Twitter QR Code',
@ -93,51 +82,28 @@ const jsonLd = {
], ],
totalTime: 'PT30S', totalTime: 'PT30S',
}, },
{ generateFaqSchema({
'@type': 'FAQPage', 'Does it work for both Twitter and X?': {
mainEntity: [ question: 'Does it work for both Twitter and X?',
{ answer: 'Yes, they are the same platform. The QR code links to x.com, which is the current standard, but works for twitter.com links too.',
'@type': 'Question', },
name: 'Does it work for both Twitter and X?', 'Can I link to a specific tweet?': {
acceptedAnswer: { question: 'Can I link to a specific tweet?',
'@type': 'Answer', answer: 'Yes! Just paste the full URL of the tweet into the input field instead of your username.',
text: 'Yes, they are the same platform. The QR code links to x.com, which is the current standard, but works for twitter.com links too.', },
}, 'Is it free?': {
}, question: 'Is it free?',
{ answer: 'Yes, generating this QR code is completely free and requires no signup.',
'@type': 'Question', },
name: 'Can I link to a specific tweet?', 'Can I track scans?': {
acceptedAnswer: { question: 'Can I track scans?',
'@type': 'Answer', answer: 'This is a static QR code, so tracking is not included. Use our Dynamic QR Code generator for analytics.',
text: 'Yes! Just paste the full URL of the tweet into the input field instead of your username.', },
}, 'What if I change my handle?': {
}, question: 'What if I change my handle?',
{ answer: 'If you change your handle, the link in the QR code will break. You will need to generate a new QR code.',
'@type': 'Question', },
name: 'Is it free?', }),
acceptedAnswer: {
'@type': 'Answer',
text: 'Yes, generating this QR code is completely free and requires no signup.',
},
},
{
'@type': 'Question',
name: 'Can I track scans?',
acceptedAnswer: {
'@type': 'Answer',
text: 'This is a static QR code, so tracking is not included. Use our Dynamic QR Code generator for analytics.',
},
},
{
'@type': 'Question',
name: 'What if I change my handle?',
acceptedAnswer: {
'@type': 'Answer',
text: 'If you change your handle, the link in the QR code will break. You will need to generate a new QR code.',
},
},
],
},
], ],
}; };

View File

@ -5,6 +5,7 @@ import { Link as LinkIcon, Shield, Zap, Smartphone, Globe } from 'lucide-react';
import { QRCodeSVG } from 'qrcode.react'; import { QRCodeSVG } from 'qrcode.react';
import { ToolBreadcrumb } from '@/components/seo/BreadcrumbSchema'; import { ToolBreadcrumb } from '@/components/seo/BreadcrumbSchema';
import { RelatedTools } from '@/components/marketing/RelatedTools'; import { RelatedTools } from '@/components/marketing/RelatedTools';
import { generateSoftwareAppSchema, generateFaqSchema } from '@/lib/schema-utils';
// SEO Optimized Metadata // SEO Optimized Metadata
export const metadata: Metadata = { export const metadata: Metadata = {
@ -38,23 +39,11 @@ export const metadata: Metadata = {
const jsonLd = { const jsonLd = {
'@context': 'https://schema.org', '@context': 'https://schema.org',
'@graph': [ '@graph': [
{ generateSoftwareAppSchema(
'@type': 'SoftwareApplication', 'URL QR Code Generator',
name: 'URL QR Code Generator', 'Generate QR codes for URLs and websites. Direct linking, no redirects.',
applicationCategory: 'UtilitiesApplication', '/og-url-generator.png'
operatingSystem: 'Web Browser', ),
offers: {
'@type': 'Offer',
price: '0',
priceCurrency: 'USD',
},
aggregateRating: {
'@type': 'AggregateRating',
ratingValue: '4.9',
ratingCount: '3100',
},
description: 'Generate QR codes for URLs and websites. Direct linking, no redirects.',
},
{ {
'@type': 'HowTo', '@type': 'HowTo',
name: 'How to Create a URL QR Code', name: 'How to Create a URL QR Code',
@ -81,43 +70,24 @@ const jsonLd = {
], ],
totalTime: 'PT20S', totalTime: 'PT20S',
}, },
{ generateFaqSchema({
'@type': 'FAQPage', 'Do these QR codes expire?': {
mainEntity: [ question: 'Do these QR codes expire?',
{ answer: 'No. These are static QR codes. They directly encode your URL and will work forever as long as your website is online.',
'@type': 'Question', },
name: 'Do these QR codes expire?', 'Can I track how many people scan it?': {
acceptedAnswer: { question: 'Can I track how many people scan it?',
'@type': 'Answer', answer: 'No, static QR codes cannot be tracked. If you need scan usage analytics (location, device, time), you should use our Dynamic QR Code generator.',
text: 'No. These are static QR codes. They directly encode your URL and will work forever as long as your website is online.', },
}, 'Can I change the destination URL later?': {
}, question: 'Can I change the destination URL later?',
{ answer: 'No. Once a static QR code is printed, it cannot be changed. If you change your website URL, you will need to print a new code. Use Dynamic QR Codes if you need flexibility.',
'@type': 'Question', },
name: 'Can I track how many people scan it?', 'Is there a scan limit?': {
acceptedAnswer: { question: 'Is there a scan limit?',
'@type': 'Answer', answer: 'No. There are zero limits on how many times your QR code can be scanned.',
text: 'No, static QR codes cannot be tracked. If you need scan usage analytics (location, device, time), you should use our Dynamic QR Code generator.', },
}, }),
},
{
'@type': 'Question',
name: 'Can I change the destination URL later?',
acceptedAnswer: {
'@type': 'Answer',
text: 'No. Once a static QR code is printed, it cannot be changed. If you change your website URL, you will need to print a new code. Use Dynamic QR Codes if you need flexibility.',
},
},
{
'@type': 'Question',
name: 'Is there a scan limit?',
acceptedAnswer: {
'@type': 'Answer',
text: 'No. There are zero limits on how many times your QR code can be scanned.',
},
},
],
},
], ],
}; };

View File

@ -5,11 +5,12 @@ import { User, Shield, Zap, Smartphone, Contact, Share2, Check, UserPlus } from
import { QRCodeSVG } from 'qrcode.react'; import { QRCodeSVG } from 'qrcode.react';
import { ToolBreadcrumb } from '@/components/seo/BreadcrumbSchema'; import { ToolBreadcrumb } from '@/components/seo/BreadcrumbSchema';
import { RelatedTools } from '@/components/marketing/RelatedTools'; import { RelatedTools } from '@/components/marketing/RelatedTools';
import { generateSoftwareAppSchema, generateFaqSchema } from '@/lib/schema-utils';
// SEO Optimized Metadata // SEO Optimized Metadata
export const metadata: Metadata = { export const metadata: Metadata = {
title: { title: {
absolute: 'Free vCard QR Code Generator | Digitale Visitenkarte Erstellen | QR Master', absolute: 'vCard QR Code Generator | Digitale Visitenkarte | QR Master',
}, },
description: 'Create a vCard QR code for your business card. Erstelle deine elektronische Visitenkarte kostenlos. Share contact details instantly. Free & No App Required.', description: 'Create a vCard QR code for your business card. Erstelle deine elektronische Visitenkarte kostenlos. Share contact details instantly. Free & No App Required.',
keywords: ['vcard qr code', 'business card qr code', 'contact qr generator', 'digital business card', 'add to contacts qr', 'visitenkarte qr code', 'digitale visitenkarte erstellen', 'kontakt qr code', 'elektronische visitenkarte', 'vcard erstellen kostenlos'], keywords: ['vcard qr code', 'business card qr code', 'contact qr generator', 'digital business card', 'add to contacts qr', 'visitenkarte qr code', 'digitale visitenkarte erstellen', 'kontakt qr code', 'elektronische visitenkarte', 'vcard erstellen kostenlos'],
@ -38,23 +39,11 @@ export const metadata: Metadata = {
const jsonLd = { const jsonLd = {
'@context': 'https://schema.org', '@context': 'https://schema.org',
'@graph': [ '@graph': [
{ generateSoftwareAppSchema(
'@type': 'SoftwareApplication', 'vCard QR Code Generator',
name: 'vCard QR Code Generator', 'Generate vCard (VCF) QR codes for business cards. Scanners can save contact info instantly.',
applicationCategory: 'UtilitiesApplication', '/og-vcard-generator.png'
operatingSystem: 'Web Browser', ),
offers: {
'@type': 'Offer',
price: '0',
priceCurrency: 'USD',
},
aggregateRating: {
'@type': 'AggregateRating',
ratingValue: '4.9',
ratingCount: '4200',
},
description: 'Generate vCard (VCF) QR codes for business cards. Scanners can save contact info instantly.',
},
{ {
'@type': 'HowTo', '@type': 'HowTo',
name: 'How to Create a vCard QR Code', name: 'How to Create a vCard QR Code',
@ -81,43 +70,24 @@ const jsonLd = {
], ],
totalTime: 'PT1M', totalTime: 'PT1M',
}, },
{ generateFaqSchema({
'@type': 'FAQPage', 'How does a vCard QR code work?': {
mainEntity: [ question: 'How does a vCard QR code work?',
{ answer: 'A vCard QR code contains your contact information in a standardized format (VCF). When scanned, the phone recognizes it as a contact card and prompts the user to "Save Contact" to their address book.',
'@type': 'Question', },
name: 'How does a vCard QR code work?', 'Is there a limit to how much info I can add?': {
acceptedAnswer: { question: 'Is there a limit to how much info I can add?',
'@type': 'Answer', answer: 'Static QR codes hold data directly in the pattern. The more data you add (long addresses, bio), the denser and harder to scan the QR code becomes. We recommend sticking to essential contact info for static codes.',
text: 'A vCard QR code contains your contact information in a standardized format (VCF). When scanned, the phone recognizes it as a contact card and prompts the user to "Save Contact" to their address book.', },
}, 'Can I update my info later?': {
}, question: 'Can I update my info later?',
{ answer: 'No. This is a static vCard QR code. Once created, the info cannot be changed. If you move jobs or change numbers, you must print a new code. For editable cards, use our Dynamic vCard Plus.',
'@type': 'Question', },
name: 'Is there a limit to how much info I can add?', 'Does it work on iPhone and Android?': {
acceptedAnswer: { question: 'Does it work on iPhone and Android?',
'@type': 'Answer', answer: 'Yes. Both iOS (Camera app) and Android (Camera or Google Lens) natively support vCard QR codes and correctly import the contact data.',
text: 'Static QR codes hold data directly in the pattern. The more data you add (long addresses, bio), the denser and harder to scan the QR code becomes. We recommend sticking to essential contact info for static codes.', },
}, }),
},
{
'@type': 'Question',
name: 'Can I update my info later?',
acceptedAnswer: {
'@type': 'Answer',
text: 'No. This is a static vCard QR code. Once created, the info cannot be changed. If you move jobs or change numbers, you must print a new code. For editable cards, use our Dynamic vCard Plus.',
},
},
{
'@type': 'Question',
name: 'Does it work on iPhone and Android?',
acceptedAnswer: {
'@type': 'Answer',
text: 'Yes. Both iOS (Camera app) and Android (Camera or Google Lens) natively support vCard QR codes and correctly import the contact data.',
},
},
],
},
], ],
}; };

View File

@ -5,6 +5,7 @@ import { MessageCircle, Shield, Zap, Smartphone, Send, Phone, Download, Check }
import { QRCodeSVG } from 'qrcode.react'; import { QRCodeSVG } from 'qrcode.react';
import { ToolBreadcrumb } from '@/components/seo/BreadcrumbSchema'; import { ToolBreadcrumb } from '@/components/seo/BreadcrumbSchema';
import { RelatedTools } from '@/components/marketing/RelatedTools'; import { RelatedTools } from '@/components/marketing/RelatedTools';
import { generateSoftwareAppSchema, generateFaqSchema } from '@/lib/schema-utils';
// SEO Optimized Metadata // SEO Optimized Metadata
export const metadata: Metadata = { export const metadata: Metadata = {
@ -38,23 +39,11 @@ export const metadata: Metadata = {
const jsonLd = { const jsonLd = {
'@context': 'https://schema.org', '@context': 'https://schema.org',
'@graph': [ '@graph': [
{ generateSoftwareAppSchema(
'@type': 'SoftwareApplication', 'WhatsApp QR Code Generator',
name: 'WhatsApp QR Code Generator', 'Generate QR codes that start a WhatsApp conversation with a specific number.',
applicationCategory: 'UtilitiesApplication', '/og-whatsapp-generator.png'
operatingSystem: 'Web Browser', ),
offers: {
'@type': 'Offer',
price: '0',
priceCurrency: 'USD',
},
aggregateRating: {
'@type': 'AggregateRating',
ratingValue: '4.8',
ratingCount: '2300',
},
description: 'Generate QR codes that start a WhatsApp conversation with a specific number.',
},
{ {
'@type': 'HowTo', '@type': 'HowTo',
name: 'How to Create a WhatsApp QR Code', name: 'How to Create a WhatsApp QR Code',
@ -93,51 +82,28 @@ const jsonLd = {
], ],
totalTime: 'PT45S', totalTime: 'PT45S',
}, },
{ generateFaqSchema({
'@type': 'FAQPage', 'Do users need to save my number first?': {
mainEntity: [ question: 'Do users need to save my number first?',
{ answer: 'No! That is the best part. Scanning the code opens the chat immediately without them needing to save you as a contact first.',
'@type': 'Question', },
name: 'Do users need to save my number first?', 'Can I use this for WhatsApp Business?': {
acceptedAnswer: { question: 'Can I use this for WhatsApp Business?',
'@type': 'Answer', answer: 'Yes, it works perfectly for both personal and business accounts.',
text: 'No! That is the best part. Scanning the code opens the chat immediately without them needing to save you as a contact first.', },
}, 'What is the Pre-filled Message?': {
}, question: 'What is the Pre-filled Message?',
{ answer: 'It is text that automatically appears in the user\'s typing field when they scan the code (e.g., "Hello, I want to order pizza"). They just have to hit send.',
'@type': 'Question', },
name: 'Can I use this for WhatsApp Business?', 'Is it free?': {
acceptedAnswer: { question: 'Is it free?',
'@type': 'Answer', answer: 'Yes, this generator is completely free.',
text: 'Yes, it works perfectly for both personal and business accounts.', },
}, 'Can I track scans?': {
}, question: 'Can I track scans?',
{ answer: 'This is a static QR code, so tracking is not included. Use our Dynamic QR Code generator for analytics.',
'@type': 'Question', },
name: 'What is the Pre-filled Message?', }),
acceptedAnswer: {
'@type': 'Answer',
text: 'It is text that automatically appears in the user\'s typing field when they scan the code (e.g., "Hello, I want to order pizza"). They just have to hit send.',
},
},
{
'@type': 'Question',
name: 'Is it free?',
acceptedAnswer: {
'@type': 'Answer',
text: 'Yes, this generator is completely free.',
},
},
{
'@type': 'Question',
name: 'Can I track scans?',
acceptedAnswer: {
'@type': 'Answer',
text: 'This is a static QR code, so tracking is not included. Use our Dynamic QR Code generator for analytics.',
},
},
],
},
], ],
}; };

View File

@ -5,6 +5,7 @@ import { Wifi, Shield, Zap, Smartphone, Lock, QrCode, Download, Share2 } from 'l
import { QRCodeSVG } from 'qrcode.react'; import { QRCodeSVG } from 'qrcode.react';
import { ToolBreadcrumb } from '@/components/seo/BreadcrumbSchema'; import { ToolBreadcrumb } from '@/components/seo/BreadcrumbSchema';
import { RelatedTools } from '@/components/marketing/RelatedTools'; import { RelatedTools } from '@/components/marketing/RelatedTools';
import { generateSoftwareAppSchema, generateFaqSchema } from '@/lib/schema-utils';
// SEO Optimized Metadata // SEO Optimized Metadata
export const metadata: Metadata = { export const metadata: Metadata = {
@ -39,23 +40,11 @@ const jsonLd = {
'@context': 'https://schema.org', '@context': 'https://schema.org',
'@graph': [ '@graph': [
// SoftwareApplication Schema // SoftwareApplication Schema
{ generateSoftwareAppSchema(
'@type': 'SoftwareApplication', 'WiFi QR Code Generator',
name: 'WiFi QR Code Generator', 'Generate QR codes for WiFi networks. Guests scan to connect without typing passwords.',
applicationCategory: 'UtilitiesApplication', '/og-wifi-generator.png'
operatingSystem: 'Web Browser', ),
offers: {
'@type': 'Offer',
price: '0',
priceCurrency: 'USD',
},
aggregateRating: {
'@type': 'AggregateRating',
ratingValue: '4.9',
ratingCount: '2847',
},
description: 'Generate QR codes for WiFi networks. Guests scan to connect without typing passwords.',
},
// HowTo Schema for Featured Snippets // HowTo Schema for Featured Snippets
{ {
'@type': 'HowTo', '@type': 'HowTo',
@ -96,51 +85,28 @@ const jsonLd = {
totalTime: 'PT1M', totalTime: 'PT1M',
}, },
// FAQPage Schema // FAQPage Schema
{ generateFaqSchema({
'@type': 'FAQPage', 'Is it safe to enter my WiFi password?': {
mainEntity: [ question: 'Is it safe to enter my WiFi password?',
{ answer: 'Yes, completely safe. This tool processes everything in your browser (client-side). Your password never leaves your device and is not sent to any server.',
'@type': 'Question', },
name: 'Is it safe to enter my WiFi password?', 'Do WiFi QR codes work on iPhone and Android?': {
acceptedAnswer: { question: 'Do WiFi QR codes work on iPhone and Android?',
'@type': 'Answer', answer: 'Yes. Both iOS (11+) and Android devices can scan WiFi QR codes using their built-in camera app. No additional apps required.',
text: 'Yes, completely safe. This tool processes everything in your browser (client-side). Your password never leaves your device and is not sent to any server.', },
}, 'What happens if I change my WiFi password?': {
}, question: 'What happens if I change my WiFi password?',
{ answer: 'If you change your WiFi password, the old QR code will stop working. You\'ll need to generate a new QR code with the updated credentials.For frequently changing passwords, consider using dynamic QR codes.',
'@type': 'Question', },
name: 'Do WiFi QR codes work on iPhone and Android?', 'Can I customize the QR code design?': {
acceptedAnswer: { question: 'Can I customize the QR code design?',
'@type': 'Answer', answer: 'Yes. You can change the QR code color and add frame labels like "Scan Me" or "WiFi" to make it more recognizable and user-friendly.',
text: 'Yes. Both iOS (11+) and Android devices can scan WiFi QR codes using their built-in camera app. No additional apps required.', },
}, 'Does it work for hidden networks?': {
}, question: 'Does it work for hidden networks?',
{ answer: 'Yes, just check the "Hidden Network" box if your SSID is hidden. The QR code contains the standard WiFi string configuration.',
'@type': 'Question', },
name: 'What happens if I change my WiFi password?', }),
acceptedAnswer: {
'@type': 'Answer',
text: 'You will need to generate a new QR code with the updated password. Consider using dynamic QR codes if you change passwords frequently.',
},
},
{
'@type': 'Question',
name: 'Can I customize the QR code design?',
acceptedAnswer: {
'@type': 'Answer',
text: 'Yes. You can change the QR code color and add frame labels like "Scan Me" or "WiFi" to make it more recognizable.',
},
},
{
'@type': 'Question',
name: 'Does it work for hidden networks?',
acceptedAnswer: {
'@type': 'Answer',
text: 'Yes, just check the "Hidden Network" box if your SSID is hidden. The QR code contains the standard WiFi string configuration.',
},
},
],
},
], ],
}; };

View File

@ -5,6 +5,7 @@ import { Youtube, Shield, Zap, Smartphone, Play, Radio, Download, Share2 } from
import { QRCodeSVG } from 'qrcode.react'; import { QRCodeSVG } from 'qrcode.react';
import { ToolBreadcrumb } from '@/components/seo/BreadcrumbSchema'; import { ToolBreadcrumb } from '@/components/seo/BreadcrumbSchema';
import { RelatedTools } from '@/components/marketing/RelatedTools'; import { RelatedTools } from '@/components/marketing/RelatedTools';
import { generateSoftwareAppSchema, generateFaqSchema } from '@/lib/schema-utils';
// SEO Optimized Metadata // SEO Optimized Metadata
export const metadata: Metadata = { export const metadata: Metadata = {
@ -38,23 +39,11 @@ export const metadata: Metadata = {
const jsonLd = { const jsonLd = {
'@context': 'https://schema.org', '@context': 'https://schema.org',
'@graph': [ '@graph': [
{ generateSoftwareAppSchema(
'@type': 'SoftwareApplication', 'YouTube QR Code Generator',
name: 'YouTube QR Code Generator', 'Generate QR codes that direct users to a YouTube video or channel.',
applicationCategory: 'UtilitiesApplication', '/og-youtube-generator.png'
operatingSystem: 'Web Browser', ),
offers: {
'@type': 'Offer',
price: '0',
priceCurrency: 'USD',
},
aggregateRating: {
'@type': 'AggregateRating',
ratingValue: '4.8',
ratingCount: '1340',
},
description: 'Generate QR codes that direct users to a YouTube video or channel.',
},
{ {
'@type': 'HowTo', '@type': 'HowTo',
name: 'How to Create a YouTube QR Code', name: 'How to Create a YouTube QR Code',
@ -93,51 +82,28 @@ const jsonLd = {
], ],
totalTime: 'PT30S', totalTime: 'PT30S',
}, },
{ generateFaqSchema({
'@type': 'FAQPage', 'Does it open the YouTube app?': {
mainEntity: [ question: 'Does it open the YouTube app?',
{ answer: 'Yes! If the user has the YouTube app installed, the QR code will automatically launch the app and play the video.',
'@type': 'Question', },
name: 'Does it open the YouTube app?', 'Can I link to a specific timestamp?': {
acceptedAnswer: { question: 'Can I link to a specific timestamp?',
'@type': 'Answer', answer: 'Yes. If you include the timestamp in your YouTube link (e.g., ?t=60s), the video will start playing from that exact moment.',
text: 'Yes! If the user has the YouTube app installed, the QR code will automatically launch the app and play the video.', },
}, 'Can I use this for a playlist?': {
}, question: 'Can I use this for a playlist?',
{ answer: 'Absolutely. Just paste the playlist URL, and users will be taken to the full list of videos.',
'@type': 'Question', },
name: 'Can I link to a specific timestamp?', 'Is it free?': {
acceptedAnswer: { question: 'Is it free?',
'@type': 'Answer', answer: 'Yes, this tool is 100% free forever.',
text: 'Yes. If you include the timestamp in your YouTube link (e.g., ?t=60s), the video will start playing from that exact moment.', },
}, 'Does it work for YouTube Shorts?': {
}, question: 'Does it work for YouTube Shorts?',
{ answer: 'Yes, just paste the "Share" link from any YouTube Short.',
'@type': 'Question', },
name: 'Can I use this for a playlist?', }),
acceptedAnswer: {
'@type': 'Answer',
text: 'Absolutely. Just paste the playlist URL, and users will be taken to the full list of videos.',
},
},
{
'@type': 'Question',
name: 'Is it free?',
acceptedAnswer: {
'@type': 'Answer',
text: 'Yes, this tool is 100% free forever.',
},
},
{
'@type': 'Question',
name: 'Does it work for YouTube Shorts?',
acceptedAnswer: {
'@type': 'Answer',
text: 'Yes, just paste the "Share" link from any YouTube Short.',
},
},
],
},
], ],
}; };

View File

@ -5,6 +5,7 @@ import { Video, Shield, Zap, Smartphone, Users, Download, Share2 } from 'lucide-
import { QRCodeSVG } from 'qrcode.react'; import { QRCodeSVG } from 'qrcode.react';
import { ToolBreadcrumb } from '@/components/seo/BreadcrumbSchema'; import { ToolBreadcrumb } from '@/components/seo/BreadcrumbSchema';
import { RelatedTools } from '@/components/marketing/RelatedTools'; import { RelatedTools } from '@/components/marketing/RelatedTools';
import { generateSoftwareAppSchema, generateFaqSchema } from '@/lib/schema-utils';
// SEO Optimized Metadata // SEO Optimized Metadata
export const metadata: Metadata = { export const metadata: Metadata = {
@ -38,23 +39,12 @@ export const metadata: Metadata = {
const jsonLd = { const jsonLd = {
'@context': 'https://schema.org', '@context': 'https://schema.org',
'@graph': [ '@graph': [
{ generateSoftwareAppSchema(
'@type': 'SoftwareApplication', 'Zoom QR Code Generator',
name: 'Zoom QR Code Generator', 'Generate QR codes that let people join your Zoom meeting with one scan.',
applicationCategory: 'BusinessApplication', '/og-zoom-generator.png',
operatingSystem: 'Web Browser', 'BusinessApplication'
offers: { ),
'@type': 'Offer',
price: '0',
priceCurrency: 'USD',
},
aggregateRating: {
'@type': 'AggregateRating',
ratingValue: '4.8',
ratingCount: '720',
},
description: 'Generate QR codes that let people join your Zoom meeting with one scan.',
},
{ {
'@type': 'HowTo', '@type': 'HowTo',
name: 'How to Create a Zoom QR Code', name: 'How to Create a Zoom QR Code',
@ -87,43 +77,24 @@ const jsonLd = {
], ],
totalTime: 'PT30S', totalTime: 'PT30S',
}, },
{ generateFaqSchema({
'@type': 'FAQPage', 'What happens when someone scans the QR code?': {
mainEntity: [ question: 'What happens when someone scans the QR code?',
{ answer: 'The Zoom app opens directly with your meeting ID and passcode pre-filled. They just tap "Join" to enter the meeting.',
'@type': 'Question', },
name: 'What happens when someone scans the QR code?', 'Does it work for recurring meetings?': {
acceptedAnswer: { question: 'Does it work for recurring meetings?',
'@type': 'Answer', answer: 'Yes! If your recurring meeting uses a fixed Personal Meeting ID (PMI), the QR code will work for all sessions.',
text: 'The Zoom app opens directly with your meeting ID and passcode pre-filled. They just tap "Join" to enter the meeting.', },
}, 'What if the meeting ID changes?': {
}, question: 'What if the meeting ID changes?',
{ answer: 'Static QR codes cannot be updated. You\'ll need to generate a new code. For changeable meetings, consider our Dynamic QR Codes.',
'@type': 'Question', },
name: 'Does it work for recurring meetings?', 'Does it work on all devices?': {
acceptedAnswer: { question: 'Does it work on all devices?',
'@type': 'Answer', answer: 'Yes. The QR code works on iOS, Android, and can also open Zoom on desktop computers if the Zoom app is installed.',
text: 'Yes! If your recurring meeting uses a fixed Personal Meeting ID (PMI), the QR code will work for all sessions.', },
}, }),
},
{
'@type': 'Question',
name: 'What if the meeting ID changes?',
acceptedAnswer: {
'@type': 'Answer',
text: 'Static QR codes cannot be updated. You\'ll need to generate a new code. For changeable meetings, consider our Dynamic QR Codes.',
},
},
{
'@type': 'Question',
name: 'Does it work on all devices?',
acceptedAnswer: {
'@type': 'Answer',
text: 'Yes. The QR code works on iOS, Android, and can also open Zoom on desktop computers if the Zoom app is installed.',
},
},
],
},
], ],
}; };

View File

@ -52,6 +52,14 @@ export async function generateMetadata(): Promise<Metadata> {
url: 'https://www.qrmaster.net/qr-code-erstellen', url: 'https://www.qrmaster.net/qr-code-erstellen',
type: 'website', type: 'website',
locale: 'de_DE', locale: 'de_DE',
images: [
{
url: 'https://www.qrmaster.net/og-image.png',
width: 1200,
height: 630,
alt: 'QR Code Erstellen - Kostenlos & Sofort',
},
],
}, },
twitter: { twitter: {
title: 'QR Code Erstellen Kostenlos | QR Master', title: 'QR Code Erstellen Kostenlos | QR Master',

View File

@ -1,4 +1,5 @@
import { MetadataRoute } from 'next'; import { MetadataRoute } from 'next';
import { blogPostList } from '../lib/blog-data';
export default function sitemap(): MetadataRoute.Sitemap { export default function sitemap(): MetadataRoute.Sitemap {
const baseUrl = 'https://www.qrmaster.net'; const baseUrl = 'https://www.qrmaster.net';
@ -27,20 +28,9 @@ export default function sitemap(): MetadataRoute.Sitemap {
]; ];
// All blog posts // All blog posts
const blogPosts = [ const blogPages = blogPostList.map((post) => ({
'qr-code-restaurant-menu', url: `${baseUrl}/blog/${post.slug}`,
'vcard-qr-code-generator', lastModified: post.dateModified ? new Date(post.dateModified) : new Date(),
'qr-code-small-business',
'qr-code-print-size-guide',
'qr-code-tracking-guide-2025',
'dynamic-vs-static-qr-codes',
'bulk-qr-code-generator-excel',
'qr-code-analytics',
];
const blogPages = blogPosts.map((slug) => ({
url: `${baseUrl}/blog/${slug}`,
lastModified: new Date(),
changeFrequency: 'monthly' as const, changeFrequency: 'monthly' as const,
priority: 0.8, priority: 0.8,
})); }));
@ -119,12 +109,7 @@ export default function sitemap(): MetadataRoute.Sitemap {
changeFrequency: 'yearly', changeFrequency: 'yearly',
priority: 0.4, priority: 0.4,
}, },
{
url: `${baseUrl}/terms`,
lastModified: new Date(),
changeFrequency: 'yearly',
priority: 0.4,
},
...toolPages, ...toolPages,
...blogPages, ...blogPages,
]; ];

View File

@ -4,10 +4,30 @@ import { useEffect, useState, useRef } from 'react';
import { usePathname, useSearchParams } from 'next/navigation'; import { usePathname, useSearchParams } from 'next/navigation';
import posthog from 'posthog-js'; import posthog from 'posthog-js';
export function PostHogProvider({ children }: { children: React.ReactNode }) { export function PostHogPageView() {
const pathname = usePathname(); const pathname = usePathname();
const searchParams = useSearchParams(); const searchParams = useSearchParams();
const [isInitialized, setIsInitialized] = useState(false);
// Track page views
useEffect(() => {
const cookieConsent = localStorage.getItem('cookieConsent');
if (cookieConsent === 'accepted' && pathname) {
let url = window.origin + pathname;
if (searchParams && searchParams.toString()) {
url = url + `?${searchParams.toString()}`;
}
posthog.capture('$pageview', {
$current_url: url,
});
}
}, [pathname, searchParams]);
return null;
}
export function PostHogProvider({ children }: { children: React.ReactNode }) {
const initializationAttempted = useRef(false); const initializationAttempted = useRef(false);
// Initialize PostHog once // Initialize PostHog once
@ -18,6 +38,9 @@ export function PostHogProvider({ children }: { children: React.ReactNode }) {
const cookieConsent = localStorage.getItem('cookieConsent'); const cookieConsent = localStorage.getItem('cookieConsent');
// Check if we should initialize based on consent
// If not accepted yet, we don't init. CookieBanner deals with setting 'accepted' and reloading or calling init.
// Ideally we should listen to consent changes, but for now matching previous behavior.
if (cookieConsent === 'accepted') { if (cookieConsent === 'accepted') {
const apiKey = process.env.NEXT_PUBLIC_POSTHOG_KEY; const apiKey = process.env.NEXT_PUBLIC_POSTHOG_KEY;
const apiHost = process.env.NEXT_PUBLIC_POSTHOG_HOST; const apiHost = process.env.NEXT_PUBLIC_POSTHOG_HOST;
@ -27,49 +50,24 @@ export function PostHogProvider({ children }: { children: React.ReactNode }) {
return; return;
} }
// Check if already initialized (using _loaded property)
if (!(posthog as any)._loaded) { if (!(posthog as any)._loaded) {
posthog.init(apiKey, { posthog.init(apiKey, {
api_host: apiHost || 'https://us.i.posthog.com', api_host: apiHost || 'https://us.i.posthog.com',
person_profiles: 'identified_only', person_profiles: 'identified_only',
capture_pageview: false, // Manual pageview tracking capture_pageview: false, // We handle this manually
capture_pageleave: true, capture_pageleave: true,
autocapture: true, autocapture: true,
respect_dnt: true, respect_dnt: true,
opt_out_capturing_by_default: false, opt_out_capturing_by_default: false,
}); });
// Enable debug mode in development
if (process.env.NODE_ENV === 'development') { if (process.env.NODE_ENV === 'development') {
posthog.debug(); posthog.debug();
} }
// Set initialized immediately after init
setIsInitialized(true);
} else {
setIsInitialized(true); // Already loaded
} }
} }
// NO cleanup function - PostHog should persist across page navigation
}, []); }, []);
// Track page views ONLY after PostHog is initialized
useEffect(() => {
const cookieConsent = localStorage.getItem('cookieConsent');
if (cookieConsent === 'accepted' && pathname && isInitialized) {
let url = window.origin + pathname;
if (searchParams && searchParams.toString()) {
url = url + `?${searchParams.toString()}`;
}
posthog.capture('$pageview', {
$current_url: url,
});
}
}, [pathname, searchParams, isInitialized]); // Added isInitialized dependency
return <>{children}</>; return <>{children}</>;
} }

View File

@ -3,19 +3,20 @@
import { Suspense } from 'react'; import { Suspense } from 'react';
import { ToastContainer } from '@/components/ui/Toast'; import { ToastContainer } from '@/components/ui/Toast';
import AuthProvider from '@/components/SessionProvider'; import AuthProvider from '@/components/SessionProvider';
import { PostHogProvider } from '@/components/PostHogProvider'; import { PostHogProvider, PostHogPageView } from '@/components/PostHogProvider';
import CookieBanner from '@/components/CookieBanner'; import CookieBanner from '@/components/CookieBanner';
export function Providers({ children }: { children: React.ReactNode }) { export function Providers({ children }: { children: React.ReactNode }) {
return ( return (
<Suspense fallback={null}> <PostHogProvider>
<PostHogProvider> <Suspense fallback={null}>
<AuthProvider> <PostHogPageView />
{children} </Suspense>
</AuthProvider> <AuthProvider>
<CookieBanner /> {children}
<ToastContainer /> </AuthProvider>
</PostHogProvider> <CookieBanner />
</Suspense> <ToastContainer />
</PostHogProvider>
); );
} }

View File

@ -17,7 +17,7 @@ export function Footer({ variant = 'marketing', t }: FooterProps) {
<div className="grid md:grid-cols-4 gap-8"> <div className="grid md:grid-cols-4 gap-8">
<div> <div>
<Link href="/" className="flex items-center space-x-2 mb-4 hover:opacity-80 transition-opacity"> <Link href="/" className="flex items-center space-x-2 mb-4 hover:opacity-80 transition-opacity">
<img src="/logo.svg" alt="" className="w-10 h-10" /> <img src="/logo.svg" alt="QR Master Logo" className="w-10 h-10" />
<span className={`text-xl font-bold ${isDashboard ? 'text-gray-900' : ''}`}>QR Master</span> <span className={`text-xl font-bold ${isDashboard ? 'text-gray-900' : ''}`}>QR Master</span>
</Link> </Link>
<p className={isDashboard ? 'text-gray-500' : 'text-gray-400'}> <p className={isDashboard ? 'text-gray-500' : 'text-gray-400'}>
@ -30,6 +30,7 @@ export function Footer({ variant = 'marketing', t }: FooterProps) {
<ul className={`space-y-2 ${isDashboard ? 'text-gray-500' : 'text-gray-400'}`}> <ul className={`space-y-2 ${isDashboard ? 'text-gray-500' : 'text-gray-400'}`}>
<li><Link href="/#features" className={isDashboard ? 'hover:text-primary-600' : 'hover:text-white'}>{translations.features}</Link></li> <li><Link href="/#features" className={isDashboard ? 'hover:text-primary-600' : 'hover:text-white'}>{translations.features}</Link></li>
<li><Link href="/#pricing" className={isDashboard ? 'hover:text-primary-600' : 'hover:text-white'}>{translations.pricing}</Link></li> <li><Link href="/#pricing" className={isDashboard ? 'hover:text-primary-600' : 'hover:text-white'}>{translations.pricing}</Link></li>
<li><Link href="/qr-code-tracking" className={isDashboard ? 'hover:text-primary-600' : 'hover:text-white'}>QR Analytics</Link></li>
<li><Link href="/faq" className={isDashboard ? 'hover:text-primary-600' : 'hover:text-white'}>{translations.faq}</Link></li> <li><Link href="/faq" className={isDashboard ? 'hover:text-primary-600' : 'hover:text-white'}>{translations.faq}</Link></li>
<li><Link href="/blog" className={isDashboard ? 'hover:text-primary-600' : 'hover:text-white'}>{translations.blog}</Link></li> <li><Link href="/blog" className={isDashboard ? 'hover:text-primary-600' : 'hover:text-white'}>{translations.blog}</Link></li>
</ul> </ul>

1725
src/lib/blog-data.ts Normal file

File diff suppressed because it is too large Load Diff

View File

@ -13,3 +13,30 @@ export function generateFaqSchema(questions: Record<string, { question: string;
})), })),
}; };
} }
export function generateSoftwareAppSchema(
name: string,
description: string,
imagePath: string,
applicationCategory: string = 'UtilitiesApplication'
) {
return {
'@context': 'https://schema.org',
'@type': 'SoftwareApplication',
name,
applicationCategory,
operatingSystem: 'Web Browser',
image: `https://www.qrmaster.net${imagePath}`,
offers: {
'@type': 'Offer',
price: '0',
priceCurrency: 'USD',
},
aggregateRating: {
'@type': 'AggregateRating',
ratingValue: '4.8',
ratingCount: '1250',
},
description,
};
}

View File

@ -40,21 +40,28 @@ export interface HowToTask {
totalTime?: string; totalTime?: string;
} }
const BASE_URL = 'https://www.qrmaster.net';
function toAbsoluteUrl(path: string): string {
if (path.startsWith('http')) return path;
return `${BASE_URL}${path.startsWith('/') ? '' : '/'}${path}`;
}
export function organizationSchema() { export function organizationSchema() {
return { return {
'@context': 'https://schema.org', '@context': 'https://schema.org',
'@type': 'Organization', '@type': 'Organization',
'@id': 'https://www.qrmaster.net/#organization', '@id': `${BASE_URL}/#organization`,
name: 'QR Master', name: 'QR Master',
alternateName: 'QRMaster', alternateName: 'QRMaster',
url: 'https://www.qrmaster.net', url: BASE_URL,
logo: { logo: {
'@type': 'ImageObject', '@type': 'ImageObject',
url: 'https://www.qrmaster.net/static/og-image.png', url: `${BASE_URL}/og-image.png`,
width: 1200, width: 1200,
height: 630, height: 630,
}, },
image: 'https://www.qrmaster.net/static/og-image.png', image: `${BASE_URL}/og-image.png`,
sameAs: [ sameAs: [
'https://twitter.com/qrmaster', 'https://twitter.com/qrmaster',
], ],
@ -68,8 +75,6 @@ export function organizationSchema() {
slogan: 'Dynamic QR codes that work smarter', slogan: 'Dynamic QR codes that work smarter',
foundingDate: '2025', foundingDate: '2025',
areaServed: 'Worldwide', areaServed: 'Worldwide',
serviceType: 'Software as a Service',
priceRange: '$0 - $29',
knowsAbout: [ knowsAbout: [
'QR Code Generation', 'QR Code Generation',
'Marketing Analytics', 'Marketing Analytics',
@ -121,8 +126,7 @@ export function organizationSchema() {
}, },
], ],
}, },
inLanguage: 'en', mainEntityOfPage: BASE_URL,
mainEntityOfPage: 'https://www.qrmaster.net',
}; };
} }
@ -130,19 +134,19 @@ export function websiteSchema() {
return { return {
'@context': 'https://schema.org', '@context': 'https://schema.org',
'@type': 'WebSite', '@type': 'WebSite',
'@id': 'https://www.qrmaster.net/#website', '@id': `${BASE_URL}/#website`,
name: 'QR Master', name: 'QR Master',
url: 'https://www.qrmaster.net', url: BASE_URL,
inLanguage: 'en', inLanguage: 'en',
mainEntityOfPage: 'https://www.qrmaster.net', mainEntityOfPage: BASE_URL,
publisher: { publisher: {
'@id': 'https://www.qrmaster.net/#organization', '@id': `${BASE_URL}/#organization`,
}, },
potentialAction: { potentialAction: {
'@type': 'SearchAction', '@type': 'SearchAction',
target: { target: {
'@type': 'EntryPoint', '@type': 'EntryPoint',
urlTemplate: 'https://www.qrmaster.net/blog?q={search_term_string}', urlTemplate: `${BASE_URL}/blog?q={search_term_string}`,
}, },
'query-input': 'required name=search_term_string', 'query-input': 'required name=search_term_string',
}, },
@ -153,14 +157,14 @@ export function breadcrumbSchema(items: BreadcrumbItem[]) {
return { return {
'@context': 'https://schema.org', '@context': 'https://schema.org',
'@type': 'BreadcrumbList', '@type': 'BreadcrumbList',
'@id': `https://www.qrmaster.net${items[items.length - 1]?.url}#breadcrumb`, '@id': `${BASE_URL}${items[items.length - 1]?.url}#breadcrumb`,
inLanguage: 'en', inLanguage: 'en',
mainEntityOfPage: `https://www.qrmaster.net${items[items.length - 1]?.url}`, mainEntityOfPage: `${BASE_URL}${items[items.length - 1]?.url}`,
itemListElement: items.map((item, index) => ({ itemListElement: items.map((item, index) => ({
'@type': 'ListItem', '@type': 'ListItem',
position: index + 1, position: index + 1,
name: item.name, name: item.name,
item: `https://www.qrmaster.net${item.url}`, item: toAbsoluteUrl(item.url),
})), })),
}; };
} }
@ -169,14 +173,14 @@ export function blogPostingSchema(post: BlogPost) {
return { return {
'@context': 'https://schema.org', '@context': 'https://schema.org',
'@type': 'BlogPosting', '@type': 'BlogPosting',
'@id': `https://www.qrmaster.net/blog/${post.slug}#article`, '@id': `${BASE_URL}/blog/${post.slug}#article`,
headline: post.title, headline: post.title,
description: post.description, description: post.description,
image: post.image, image: toAbsoluteUrl(post.image),
datePublished: post.datePublished, datePublished: post.datePublished,
dateModified: post.dateModified, dateModified: post.dateModified,
inLanguage: 'en', inLanguage: 'en',
mainEntityOfPage: `https://www.qrmaster.net/blog/${post.slug}`, mainEntityOfPage: `${BASE_URL}/blog/${post.slug}`,
author: { author: {
'@type': 'Person', '@type': 'Person',
name: post.author, name: post.author,
@ -185,19 +189,19 @@ export function blogPostingSchema(post: BlogPost) {
publisher: { publisher: {
'@type': 'Organization', '@type': 'Organization',
name: 'QR Master', name: 'QR Master',
url: 'https://www.qrmaster.net', url: BASE_URL,
logo: { logo: {
'@type': 'ImageObject', '@type': 'ImageObject',
url: 'https://www.qrmaster.net/static/og-image.png', url: `${BASE_URL}/og-image.png`,
width: 1200, width: 1200,
height: 630, height: 630,
}, },
}, },
isPartOf: { isPartOf: {
'@type': 'Blog', '@type': 'Blog',
'@id': 'https://www.qrmaster.net/blog#blog', '@id': `${BASE_URL}/blog#blog`,
name: 'QR Master Blog', name: 'QR Master Blog',
url: 'https://www.qrmaster.net/blog', url: `${BASE_URL}/blog`,
}, },
}; };
} }
@ -206,9 +210,9 @@ export function faqPageSchema(faqs: FAQItem[]) {
return { return {
'@context': 'https://schema.org', '@context': 'https://schema.org',
'@type': 'FAQPage', '@type': 'FAQPage',
'@id': 'https://www.qrmaster.net/faq#faqpage', '@id': `${BASE_URL}/faq#faqpage`,
inLanguage: 'en', inLanguage: 'en',
mainEntityOfPage: 'https://www.qrmaster.net/faq', mainEntityOfPage: `${BASE_URL}/faq`,
mainEntity: faqs.map((faq) => ({ mainEntity: faqs.map((faq) => ({
'@type': 'Question', '@type': 'Question',
name: faq.question, name: faq.question,
@ -224,11 +228,11 @@ export function productSchema(product: { name: string; description: string; offe
return { return {
'@context': 'https://schema.org', '@context': 'https://schema.org',
'@type': 'Product', '@type': 'Product',
'@id': 'https://www.qrmaster.net/pricing#product', '@id': `${BASE_URL}/pricing#product`,
name: product.name, name: product.name,
description: product.description, description: product.description,
inLanguage: 'en', inLanguage: 'en',
mainEntityOfPage: 'https://www.qrmaster.net/pricing', mainEntityOfPage: `${BASE_URL}/pricing`,
brand: { brand: {
'@type': 'Organization', '@type': 'Organization',
name: 'QR Master', name: 'QR Master',
@ -239,7 +243,7 @@ export function productSchema(product: { name: string; description: string; offe
price: offer.price, price: offer.price,
priceCurrency: offer.priceCurrency, priceCurrency: offer.priceCurrency,
availability: offer.availability, availability: offer.availability,
url: offer.url, url: toAbsoluteUrl(offer.url),
})), })),
}; };
} }
@ -248,18 +252,18 @@ export function howToSchema(task: HowToTask) {
return { return {
'@context': 'https://schema.org', '@context': 'https://schema.org',
'@type': 'HowTo', '@type': 'HowTo',
'@id': `https://www.qrmaster.net/blog/${task.name.toLowerCase().replace(/\s+/g, '-')}#howto`, '@id': `${BASE_URL}/blog/${task.name.toLowerCase().replace(/\s+/g, '-')}#howto`,
name: task.name, name: task.name,
description: task.description, description: task.description,
inLanguage: 'en', inLanguage: 'en',
mainEntityOfPage: `https://www.qrmaster.net/blog/${task.name.toLowerCase().replace(/\s+/g, '-')}`, mainEntityOfPage: `${BASE_URL}/blog/${task.name.toLowerCase().replace(/\s+/g, '-')}`,
totalTime: task.totalTime || 'PT5M', totalTime: task.totalTime || 'PT5M',
step: task.steps.map((step, index) => ({ step: task.steps.map((step, index) => ({
'@type': 'HowToStep', '@type': 'HowToStep',
position: index + 1, position: index + 1,
name: step.name, name: step.name,
text: step.text, text: step.text,
url: step.url, url: step.url ? toAbsoluteUrl(step.url) : undefined,
})), })),
}; };
} }