Task Tracker
Click a task to mark it complete. Progress saves in your browser automatically.
Bear Grips Dev Hub
Everything Dav needs — directory deployment + SEO setup for shops.beargrips.com. Updated March 2026.
All Tasks
Deploy Directory App
Upload, build, PM2, nginx, SSL for directory.beargrips.com. Full step-by-step with copy-paste commands.
Verify & Test
URLs to check, expected behavior, troubleshooting common issues.
SSR / Pre-Rendering
shops.beargrips.com needs server-side rendering for Google to index it. Options and verification steps.
Sitemap & Robots.txt
XML sitemap with all public pages + robots.txt to block private routes.
Meta Tags & Canonicals
Unique title, description, OG, and Twitter card tags per page. Canonical URL setup.
Schema Markup
JSON-LD structured data for Organization, Product, FAQ. Copy-paste into <head>.
Page Speed & SSL
Target 90+ PageSpeed score. Image compression, lazy loading, caching, HTTPS redirect.
Google Search Console
Verification, sitemap submission, and monitoring setup for both domains.
Favicon & Web Manifest
Browser tab icon, Apple/Android home screen icons, web manifest. Files provided — just add to site.
Vendor Shop SEO (High Priority)
Pre-rendered body content, Product schema, dynamic sitemap for vendor shops. Every vendor shop = free SEO pages.
Free Tools Pages
Deploy 7 free design tools + hub page to shops.beargrips.com/free-design-tools/. Upload, verify, add to sitemap.
Niche Landing Pages (117)
117 niche-specific landing pages (gym, church, sports, trades, etc.) targeting long-tail SEO keywords. Same tools, niche copy.
Product Catalog (85 Pages)
85 SEO pages: 1 hub + 11 category + 7 brand + 3 audience + 63 product pages. Competes with Apliiq/Printify. Images + sitemap included.
Security Hardening
Stripe protection, auth security, server headers, DDoS protection, input validation, content scraping prevention. Must-do before launch.
pSEO Pages (2,100+)
2,100+ programmatic SEO pages already deployed on Cloudflare Pages. Resources, comparisons, glossary, how-to guides, product pages, and more.
Priority Order
| # | Task | Site | Priority |
|---|---|---|---|
| 1 | Deploy Directory App (upload, build, nginx, SSL) | directory.beargrips.com | DO NOW |
| 2 | Verify directory is live and all pages work | directory.beargrips.com | DO NOW |
| 3 | SSR / Pre-Rendering for shops | shops.beargrips.com | HIGH |
| 4 | Sitemap + Robots.txt for shops | shops.beargrips.com | HIGH |
| 5 | Meta tags + canonical URLs | shops.beargrips.com | HIGH |
| 6 | Schema markup | shops.beargrips.com | MEDIUM |
| 7 | Page speed optimization | shops.beargrips.com | MEDIUM |
| 8 | Google Search Console for both domains | Both | MEDIUM |
| 9 | Vendor shop SEO (body content, schema, sitemap) | shops.beargrips.com | HIGH |
| 10 | Favicon & web manifest | shops.beargrips.com | LOW |
| 11 | Deploy Free Tools pages | shops.beargrips.com | DO NOW |
| 12 | Deploy 117 Niche Landing Pages | shops.beargrips.com | DO NOW |
| 13 | Deploy Product Catalog (85 SEO pages) | shops.beargrips.com | DO NOW |
| 14 | Security Hardening (Stripe, auth, headers, DDoS) | shops.beargrips.com | CRITICAL |
Deploy Directory App
Deploy the gym directory at directory.beargrips.com on the existing Digital Ocean server.
Server Details
| Item | Value |
|---|---|
| Server IP | 167.172.23.233 |
| Domain | directory.beargrips.com |
| App Framework | Next.js 16.1.6 |
| Node.js Required | 20+ |
| Port | 3001 (or any open port — don't conflict with shops) |
| Database | None |
| .env File | None needed |
| Suggested Path | /var/www/directory-beargrips/ |
1 Upload the Project Files
Copy the entire project folder to the server. You can SCP, rsync, or clone from git. Suggested location:
Important: The public/data/ folder contains the data files (~100MB). Make sure these are included in the upload.
2 Install & Build
SSH into the server and run:
3 Start with PM2
Start the app on port 3001 using PM2:
If PM2 is not installed:
Verify it's running:
You should see HTML output. If you see an error, check pm2 logs directory.
Save PM2 config so it restarts on reboot:
4 Nginx Server Block
Create the nginx config file:
Paste this entire config:
Enable the site and reload nginx:
Note: nginx -t tests the config. If it says "test is successful", you're good. If it shows an error, check for typos in the config file.
5 SSL Certificate
Use Let's Encrypt (certbot) to add HTTPS:
Certbot will automatically modify the nginx config to handle SSL. It also sets up auto-renewal.
If certbot is not installed:
Updating the App Later
When KJ sends you updated files:
Verify & Test
After deploying, verify these URLs work correctly.
URLs to Test
| URL | Expected |
|---|---|
https://directory.beargrips.com | Homepage with state grid, search bar, stats |
https://directory.beargrips.com/gyms/fl | Florida state page with cities grid |
https://directory.beargrips.com/gyms/fl/miami | Miami city page with gym cards + map |
https://directory.beargrips.com/gyms/ca/los-angeles | LA city page (large city, many gyms) |
https://directory.beargrips.com/api/search?q=miami | JSON search results |
Checklist
- ☐ Homepage loads with dark theme and Bear Grips branding
- ☐ Search bar works (type a city name, see dropdown results)
- ☐ State pages load (click any state from homepage)
- ☐ City pages load with gym cards and map
- ☐ Gym detail pages load (click any gym card)
- ☐ Mobile responsive (check on phone or Chrome DevTools)
- ☐ HTTPS working (no mixed content warnings)
- ☐ No 404 errors on main pages
Troubleshooting
"502 Bad Gateway"
The app isn't running. Check:
"This site can't be reached" / DNS error
DNS hasn't propagated yet. Wait 30-60 minutes after the A record was added. Check propagation:
Should return 167.172.23.233.
Build fails / Out of memory
The build generates 16,000+ pages and needs RAM. If the server has limited memory:
Port conflict
If port 3001 is in use, pick another port. Update both the PM2 start command and the nginx proxy_pass line to match.
SSR / Pre-Rendering for shops.beargrips.com
Priority: CRITICAL — If Google can't render the JavaScript, none of our SEO work matters.
Solution Options (pick one)
Option A: Pre-Rendering Service (Fastest to implement)
- Use Prerender.io or Rendertron
- Detects when a crawler visits → serves pre-rendered HTML
- No major code changes — middleware/proxy-based
- Cost: ~$15/mo
Option B: Server-Side Rendering (SSR)
- If React: use Next.js or SSR with Express
- If Vue: use Nuxt.js
- Renders on the server before sending to browser
- More work but better long-term
Option C: Static Site Generation (SSG)
- Pre-build HTML for all public pages at deploy time
- Best performance — this is what the directory app uses
- Only works for pages that don't change often (homepage, pricing, features = good fit)
How to verify it works
This should return full HTML with real content — NOT an empty <div id="app"></div>. If you see an empty div, Google sees the same thing = no indexing.
Sitemap & Robots.txt
Sitemap.xml
Create at: https://shops.beargrips.com/sitemap.xml
Notes:
- Update URLs to match actual page paths on the site
- Do NOT include dashboard/vendor pages (anything behind login)
- Do NOT include individual shop pages (
/proshops/[shopname])
Robots.txt
Place at: https://shops.beargrips.com/robots.txt
Meta Tags & Canonical URLs
Canonical URLs
Add to the <head> of every public page:
This should be dynamic — pull the current page path and build the URL. Prevents Google from treating URL variations as separate pages.
Meta Tags Infrastructure
Each public page needs these tags in <head>. KJ will provide the specific copy per page — dev just needs to wire up the infrastructure so each page can have unique values.
Framework Implementation
- React: Use
react-helmetorreact-helmet-async - Vue: Use
vue-metaor@vueuse/head - Next.js: Built-in
Headcomponent - Nuxt: Built-in
useHeadcomposable
Schema Markup
Add this JSON-LD to the <head> of the shops.beargrips.com homepage. This tells Google what the business is.
Notes:
- Update the logo URL if it's different
- This goes on the homepage only for now
- KJ will provide additional schema for specific pages later
Page Speed & SSL
Page Speed — Target 90+
Test at: pagespeed.web.dev
Common Fixes
- Compress images: Use WebP format. Tools: Squoosh or Sharp
- Lazy load images: Add
loading="lazy"to below-fold images - Minimize JS bundle: Code-split, tree-shake, remove unused dependencies
- Minimize CSS: Remove unused CSS, use PurgeCSS if applicable
- Enable gzip/brotli compression on the server (nginx)
- Cache static assets: Set
Cache-Controlheaders (e.g.,max-age=31536000for images/CSS/JS) - Preload critical resources: Fonts, above-the-fold images
- Defer non-critical JS: Add
deferorasyncto non-essential scripts
SSL / HTTPS
- All pages must load over HTTPS (no mixed content warnings)
- HTTP should 301 redirect to HTTPS automatically
- Test:
http://shops.beargrips.comshould redirect tohttps://shops.beargrips.com
Mobile Responsiveness
- Test all public pages on mobile (Chrome DevTools → Toggle Device Toolbar)
- Key breakpoints: 375px (iPhone SE), 390px (iPhone 14), 768px (iPad)
- No horizontal scrolling, text readable, buttons tappable (44px+ touch targets)
Google Search Console
We need GSC set up for both domains so we can monitor indexing and search performance.
For shops.beargrips.com
- Go to search.google.com/search-console
- Click "Add Property"
- Enter:
https://shops.beargrips.com - Choose verification method:
- DNS method (recommended): Add a TXT record to DNS for beargrips.com
- Meta tag method: Add a
<meta>tag to homepage<head> - HTML file method: Upload a verification file to root
- Once verified → Sitemaps → Submit
https://shops.beargrips.com/sitemap.xml
After adding, tell KJ so he can click "Verify" in Google Search Console.
For directory.beargrips.com
- Same process — KJ will add as separate property and provide the verification meta tag
- Enter:
https://directory.beargrips.com - Submit sitemap:
https://directory.beargrips.com/sitemap.xml - The directory app auto-generates its sitemap — it should be available at that URL once deployed
Vendor Shop SEO
Priority: HIGH — Every vendor shop and product page is a free SEO page for Bear Grips. Right now Google can see the meta tags but the page body is empty.
What's Working (Good job!)
- Pre-rendered meta tags for bots — title, description, OG tags, Twitter cards
- Vendor name in title and description
- Product mockup image in OG tags (shows when sharing links)
- Product price in OG tags (
product:price:amount) - Vendor logo as favicon per shop
Issue 0: Hide Printify Image URLs (Security)
Current (exposed):
What it should look like:
Fix: Nginx reverse proxy (quickest approach)
Add this to the nginx config for shops.beargrips.com:
Then update the app code to rewrite all Printify mockup URLs:
- Replace
https://images-api.printify.com/mockup/withhttps://shops.beargrips.com/product-images/ - This applies to: og:image, twitter:image, any <img> tags, and the Product schema image field
- The nginx proxy fetches from Printify behind the scenes — users and Google only see our domain
- 7-day cache means the same image isn't re-fetched constantly
Also check for leaks in:
- Product page JavaScript (network tab may show Printify API calls — consider proxying those too)
- Any references to "Printify" in page content, alt tags, or file names
Issue 1: Empty Body Content
Current product page body (what Google sees):
What it should look like (use the same data already in the meta tags):
Same approach for shop pages:
Key points:
- All this data is already available server-side (it's in the meta tags) — just also render it in the body
- The
<img>tag with the product mockup lets Google Images index the product photo - The product list on shop pages creates internal links Google can follow to discover all products
- Normal users will still get the JS redirect immediately — they won't see this HTML
Issue 2: Product Schema Markup
Add JSON-LD Product schema to every product page. This enables rich results in Google (price, availability, image, reviews right in search results).
Add this to the <head> of product pages (alongside existing meta tags):
Dynamic fields to populate from existing data:
| Schema Field | Source |
|---|---|
name | Product title (same as og:title minus store name) |
description | Product description (same as meta description) |
image | Product mockup URL (same as og:image) |
brand.name | Vendor store name |
price | Retail price (same as product:price:amount) |
url | Full product page URL |
availability | Always "InStock" (print on demand = always available) |
Issue 3: Dynamic Sitemap
Google needs a sitemap that includes all live vendor shops and published products. Without it, Google has to discover pages by crawling links — which is slow and incomplete.
Create a dynamic sitemap at: https://shops.beargrips.com/sitemap-shops.xml
This should auto-generate from the database, including:
Implementation notes:
- Generate dynamically from the database — query all vendors with active shops + all published products
- Only include shops/products that are live and published (not drafts)
- Update the main
robots.txtto reference this sitemap too:
Sitemap: https://shops.beargrips.com/sitemap-shops.xml - Submit to Google Search Console after creating it
- As vendors add/remove products, the sitemap auto-updates on next request
- Consider caching the sitemap for 1 hour to avoid regenerating on every request
Issue 4: Richer Default Descriptions
Most vendors keep the default shop description: "Shop at [Name]. Browse our store." — this is thin content that doesn't help SEO. Improve the auto-generated defaults so vendors get better rankings without doing extra work.
Default Shop Description (auto-generated)
Replace the current default with a richer template that pulls from the vendor's store name. Vendor can still override this if they want.
Current default:
Better default:
Default Shop Title
Current:
Better:
Default Product Page Title
Current format is good: [Product Name] - [Store Name]
Consider appending a tail keyword:
Default Product Description Enrichment
When a product uses the default system description, append a vendor-specific line at the end to make each page more unique to Google:
Why this helps vendors:
- "[Store Name] custom apparel" becomes a rankable keyword automatically
- "[Store Name] tee/hoodie/tank" product pages rank for long-tail searches
- "Free shipping" and "Printed in the USA" are trust signals Google likes to surface
- Vendors get SEO traction without writing anything themselves
- Every new product published = new indexed page with unique content
Price Display
Minor fix: Round prices to 2 decimal places in all meta tags. Currently showing raw values like 43.5552 and 26.9152.
Issue 5: Missing Favicon on Product Pages
Shop pages have the vendor's favicon but product pages are missing it. The <link rel="icon"> tag should be on all pages — shop and product.
Issue 6: Image Alt Tags
Product mockup images have no alt attribute. Google Images is a major traffic source — without alt text, our product images won't rank.
Current:
Fix — add descriptive alt text:
Pattern: alt="[Product Name] - [Store Name]"
Apply to:
- All product mockup
<img>tags in the page body - The pre-rendered
<img>in the body content (from Issue 1) - OG image tags should also get proper filenames where possible
Issue 7: Canonical URLs on Product Pages
Every public page (shop page and product page) needs a canonical tag to prevent duplicate content issues.
Add to the <head> of every shop and product page:
Build the URL dynamically from the current page path. This tells Google "this is the one true URL for this page" — prevents indexing of URL variations with query params, trailing slashes, etc.
Issue 8: Noindex Draft/Unpublished Pages
If any product or shop pages are accessible but not yet live (drafts, unpublished, deactivated), they should not be indexed by Google.
Add this to the <head> of any non-live page:
Only live, published shops and products should have index, follow. If a vendor deactivates their shop or unpublishes a product, flip to noindex.
Issue 9: OG Image Dimensions
Add width and height to OG image tags so social platforms (Facebook, LinkedIn, Twitter, iMessage) render previews instantly without fetching the image first.
Add alongside existing og:image tag:
If the actual mockup dimensions differ, use those values instead. Square (1200x1200) or landscape (1200x630) are both fine.
Issue 10: Custom 404 Page
To implement:
- Place
404.htmlin the public/root directory - Configure your app or nginx to serve this file for all 404 responses
- If using Express:
app.use((req, res) => res.status(404).sendFile('404.html')) - If using nginx fallback:
error_page 404 /404.html;
Impact
Once these fixes are in place, every vendor shop becomes a free SEO asset:
- "Gallery Barre apparel" → their shop page ranks
- "Gallery Barre tee" → their product page ranks
- Google Images → product mockups appear in image search
- Rich results → price and availability show in Google search results
- More vendors = more pages = more domain authority for shops.beargrips.com
Favicon & Web Manifest
Favicon files are ready — just add them to shops.beargrips.com. Google shows favicons in search results now, so this matters.
Files to Add
KJ will provide these files (already generated). Place them in the root/public directory of the shops app:
| File | Size | Purpose |
|---|---|---|
favicon.ico | 16+32+48px | Browser tab (legacy browsers) |
favicon-16x16.png | 16x16 | Browser tab |
favicon-32x32.png | 32x32 | Browser tab (retina) |
apple-touch-icon.png | 180x180 | iPhone home screen bookmark |
android-chrome-192x192.png | 192x192 | Android home screen |
android-chrome-512x512.png | 512x512 | Android splash screen |
HTML Tags
Add these to the <head> of every page:
Web Manifest File
Create site.webmanifest in the public/root directory:
Free Tools Pages
Deploy the 7 free design tools + hub page to shops.beargrips.com/free-design-tools/. These are static HTML files — no build step needed.
Files to Deploy
| # | File | URL on Live Site |
|---|---|---|
| 1 | index.html | /free-design-tools/ |
| 2 | background-remover.html | /free-design-tools/background-remover.html |
| 3 | image-cropper.html | /free-design-tools/image-cropper.html |
| 4 | file-compressor.html | /free-design-tools/file-compressor.html |
| 5 | transparent-png-checker.html | /free-design-tools/transparent-png-checker.html |
| 6 | image-to-png-converter.html | /free-design-tools/image-to-png-converter.html |
| 7 | image-resizer.html | /free-design-tools/image-resizer.html |
| 8 | text-design-generator.html | /free-design-tools/text-design-generator.html |
| 9 | assets/ folder | Logo, favicons (must be in /free-design-tools/assets/) |
Steps
1 Create the /free-design-tools/ directory
On the server, create the directory where the tool pages will live:
Adjust the path to match wherever the shops app serves static files from.
2 Upload all files
Upload the hub page + 7 tool pages + assets folder. Use SCP, rsync, or manual upload:
3 Verify all pages load
Open each URL in a browser and confirm they load correctly:
https://shops.beargrips.com/free-design-tools/— hub page with links to all 7 tools- Click each tool link from the hub — all 7 should load
- Bear Grips logo + favicon should appear on every page
- Check mobile (Chrome DevTools → device toolbar)
- No 404 errors, no broken assets
4 Test each tool works
For each of the 7 tools:
- Upload a test image (use any photo or logo)
- Use the tool (resize, crop, remove background, compress, check transparency, convert, generate text)
- Download the result — confirm the output file is correct
- Test on both desktop and mobile
5 Add sitemap entries
Add all 8 free tool URLs to the shops sitemap (sitemap.xml):
6 Add internal link from homepage
Add a link to /free-design-tools/ from the shops.beargrips.com homepage. Options:
- Nav bar: Add "Free Tools" link to the top navigation
- Footer: Add "Free Design Tools" to the footer link section
- Both: Nav + footer for maximum visibility and SEO juice
Link text should be: "Free Design Tools"
Niche Landing Pages (117 Pages)
Deploy 117 niche-specific landing pages to shops.beargrips.com/free-design-tools/[niche-slug]. Same 7 tools, niche-specific copy/SEO targeting long-tail keywords like "custom gym apparel" and "church t-shirt design tools."
Directory Structure
All niche pages live inside a niche/ subfolder within the free-design-tools directory:
All 117 Niche Pages to Upload
| # | File | Live URL |
|---|---|---|
| 1 | after-school-program-apparel.html | /free-design-tools/niche/after-school-program-apparel |
| 2 | auto-shop-apparel.html | /free-design-tools/niche/auto-shop-apparel |
| 3 | bachelorette-party-shirts.html | /free-design-tools/niche/bachelorette-party-shirts |
| 4 | bachelor-party-shirts.html | /free-design-tools/niche/bachelor-party-shirts |
| 5 | bakery-apparel.html | /free-design-tools/niche/bakery-apparel |
| 6 | bar-apparel.html | /free-design-tools/niche/bar-apparel |
| 7 | barbershop-apparel.html | /free-design-tools/niche/barbershop-apparel |
| 8 | barre-studio-apparel.html | /free-design-tools/niche/barre-studio-apparel |
| 9 | baseball-apparel.html | /free-design-tools/niche/baseball-apparel |
| 10 | basketball-apparel.html | /free-design-tools/niche/basketball-apparel |
| 11 | birthday-shirts.html | /free-design-tools/niche/birthday-shirts |
| 12 | boat-club-apparel.html | /free-design-tools/niche/boat-club-apparel |
| 13 | bootcamp-apparel.html | /free-design-tools/niche/bootcamp-apparel |
| 14 | boxing-gym-apparel.html | /free-design-tools/niche/boxing-gym-apparel |
| 15 | boy-scouts-apparel.html | /free-design-tools/niche/boy-scouts-apparel |
| 16 | brewery-merch.html | /free-design-tools/niche/brewery-merch |
| 17 | cafe-apparel.html | /free-design-tools/niche/cafe-apparel |
| 18 | car-club-apparel.html | /free-design-tools/niche/car-club-apparel |
| 19 | catering-apparel.html | /free-design-tools/niche/catering-apparel |
| 20 | cheerleading-apparel.html | /free-design-tools/niche/cheerleading-apparel |
| 21 | church-apparel.html | /free-design-tools/niche/church-apparel |
| 22 | college-apparel.html | /free-design-tools/niche/college-apparel |
| 23 | company-swag.html | /free-design-tools/niche/company-swag |
| 24 | conference-apparel.html | /free-design-tools/niche/conference-apparel |
| 25 | construction-apparel.html | /free-design-tools/niche/construction-apparel |
| 26 | country-club-apparel.html | /free-design-tools/niche/country-club-apparel |
| 27 | creator-merch.html | /free-design-tools/niche/creator-merch |
| 28 | cruise-apparel.html | /free-design-tools/niche/cruise-apparel |
| 29 | dance-studio-apparel.html | /free-design-tools/niche/dance-studio-apparel |
| 30 | daycare-apparel.html | /free-design-tools/niche/daycare-apparel |
| 31 | dentist-apparel.html | /free-design-tools/niche/dentist-apparel |
| 32 | dispensary-apparel.html | /free-design-tools/niche/dispensary-apparel |
| 33 | doctor-office-apparel.html | /free-design-tools/niche/doctor-office-apparel |
| 34 | dog-trainer-apparel.html | /free-design-tools/niche/dog-trainer-apparel |
| 35 | dog-walker-apparel.html | /free-design-tools/niche/dog-walker-apparel |
| 36 | dropshipping-apparel.html | /free-design-tools/niche/dropshipping-apparel |
| 37 | electrician-apparel.html | /free-design-tools/niche/electrician-apparel |
| 38 | elementary-school-apparel.html | /free-design-tools/niche/elementary-school-apparel |
| 39 | entrepreneur-apparel.html | /free-design-tools/niche/entrepreneur-apparel |
| 40 | event-planner-apparel.html | /free-design-tools/niche/event-planner-apparel |
| 41 | family-reunion-shirts.html | /free-design-tools/niche/family-reunion-shirts |
| 42 | farmers-market-apparel.html | /free-design-tools/niche/farmers-market-apparel |
| 43 | fire-department-apparel.html | /free-design-tools/niche/fire-department-apparel |
| 44 | fishing-apparel.html | /free-design-tools/niche/fishing-apparel |
| 45 | flag-football-apparel.html | /free-design-tools/niche/flag-football-apparel |
| 46 | food-truck-apparel.html | /free-design-tools/niche/food-truck-apparel |
| 47 | fraternity-sorority-apparel.html | /free-design-tools/niche/fraternity-sorority-apparel |
| 48 | functional-fitness-apparel.html | /free-design-tools/niche/functional-fitness-apparel |
| 49 | girl-scouts-apparel.html | /free-design-tools/niche/girl-scouts-apparel |
| 50 | golf-apparel.html | /free-design-tools/niche/golf-apparel |
| 51 | graduation-apparel.html | /free-design-tools/niche/graduation-apparel |
| 52 | gym-apparel.html | /free-design-tools/niche/gym-apparel |
| 53 | gymnastics-apparel.html | /free-design-tools/niche/gymnastics-apparel |
| 54 | high-school-apparel.html | /free-design-tools/niche/high-school-apparel |
| 55 | hiit-gym-apparel.html | /free-design-tools/niche/hiit-gym-apparel |
| 56 | hiking-club-apparel.html | /free-design-tools/niche/hiking-club-apparel |
| 57 | hockey-apparel.html | /free-design-tools/niche/hockey-apparel |
| 58 | hospital-apparel.html | /free-design-tools/niche/hospital-apparel |
| 59 | hvac-apparel.html | /free-design-tools/niche/hvac-apparel |
| 60 | hybrid-athlete-apparel.html | /free-design-tools/niche/hybrid-athlete-apparel |
| 61 | instagram-merch.html | /free-design-tools/niche/instagram-merch |
| 62 | insurance-apparel.html | /free-design-tools/niche/insurance-apparel |
| 63 | kickboxing-apparel.html | /free-design-tools/niche/kickboxing-apparel |
| 64 | lacrosse-apparel.html | /free-design-tools/niche/lacrosse-apparel |
| 65 | landscaping-apparel.html | /free-design-tools/niche/landscaping-apparel |
| 66 | law-firm-apparel.html | /free-design-tools/niche/law-firm-apparel |
| 67 | martial-arts-apparel.html | /free-design-tools/niche/martial-arts-apparel |
| 68 | micro-influencer-merch.html | /free-design-tools/niche/micro-influencer-merch |
| 69 | middle-school-apparel.html | /free-design-tools/niche/middle-school-apparel |
| 70 | mma-apparel.html | /free-design-tools/niche/mma-apparel |
| 71 | mortgage-apparel.html | /free-design-tools/niche/mortgage-apparel |
| 72 | nonprofit-fundraiser.html | /free-design-tools/niche/nonprofit-fundraiser |
| 73 | nurse-apparel.html | /free-design-tools/niche/nurse-apparel |
| 74 | personal-brand-merch.html | /free-design-tools/niche/personal-brand-merch |
| 75 | personal-trainer-apparel.html | /free-design-tools/niche/personal-trainer-apparel |
| 76 | pest-control-apparel.html | /free-design-tools/niche/pest-control-apparel |
| 77 | pet-business-apparel.html | /free-design-tools/niche/pet-business-apparel |
| 78 | pickleball-apparel.html | /free-design-tools/niche/pickleball-apparel |
| 79 | pilates-studio-apparel.html | /free-design-tools/niche/pilates-studio-apparel |
| 80 | pizza-shop-apparel.html | /free-design-tools/niche/pizza-shop-apparel |
| 81 | plumbing-apparel.html | /free-design-tools/niche/plumbing-apparel |
| 82 | print-on-demand-platform.html | /free-design-tools/niche/print-on-demand-platform |
| 83 | print-on-demand-side-hustle.html | /free-design-tools/niche/print-on-demand-side-hustle |
| 84 | print-on-demand-tools-2026.html | /free-design-tools/niche/print-on-demand-tools-2026 |
| 85 | private-school-apparel.html | /free-design-tools/niche/private-school-apparel |
| 86 | real-estate-apparel.html | /free-design-tools/niche/real-estate-apparel |
| 87 | rec-league-apparel.html | /free-design-tools/niche/rec-league-apparel |
| 88 | restaurant-apparel.html | /free-design-tools/niche/restaurant-apparel |
| 89 | rock-climbing-apparel.html | /free-design-tools/niche/rock-climbing-apparel |
| 90 | roofing-apparel.html | /free-design-tools/niche/roofing-apparel |
| 91 | running-club-apparel.html | /free-design-tools/niche/running-club-apparel |
| 92 | sales-team-apparel.html | /free-design-tools/niche/sales-team-apparel |
| 93 | salon-apparel.html | /free-design-tools/niche/salon-apparel |
| 94 | school-spirit-wear.html | /free-design-tools/niche/school-spirit-wear |
| 95 | side-hustle-apparel.html | /free-design-tools/niche/side-hustle-apparel |
| 96 | smoke-shop-apparel.html | /free-design-tools/niche/smoke-shop-apparel |
| 97 | soccer-apparel.html | /free-design-tools/niche/soccer-apparel |
| 98 | softball-apparel.html | /free-design-tools/niche/softball-apparel |
| 99 | spa-apparel.html | /free-design-tools/niche/spa-apparel |
| 100 | spin-studio-apparel.html | /free-design-tools/niche/spin-studio-apparel |
| 101 | startup-swag.html | /free-design-tools/niche/startup-swag |
| 102 | summer-camp-apparel.html | /free-design-tools/niche/summer-camp-apparel |
| 103 | swim-team-apparel.html | /free-design-tools/niche/swim-team-apparel |
| 104 | teacher-apparel.html | /free-design-tools/niche/teacher-apparel |
| 105 | tech-company-apparel.html | /free-design-tools/niche/tech-company-apparel |
| 106 | tennis-apparel.html | /free-design-tools/niche/tennis-apparel |
| 107 | tiktok-merch.html | /free-design-tools/niche/tiktok-merch |
| 108 | track-field-apparel.html | /free-design-tools/niche/track-field-apparel |
| 109 | university-apparel.html | /free-design-tools/niche/university-apparel |
| 110 | veterinary-apparel.html | /free-design-tools/niche/veterinary-apparel |
| 111 | volleyball-apparel.html | /free-design-tools/niche/volleyball-apparel |
| 112 | winery-apparel.html | /free-design-tools/niche/winery-apparel |
| 113 | wrestling-apparel.html | /free-design-tools/niche/wrestling-apparel |
| 114 | yoga-studio-apparel.html | /free-design-tools/niche/yoga-studio-apparel |
| 115 | youth-group-apparel.html | /free-design-tools/niche/youth-group-apparel |
| 116 | youth-sports-apparel.html | /free-design-tools/niche/youth-sports-apparel |
| 117 | youtuber-merch.html | /free-design-tools/niche/youtuber-merch |
Steps
1 Create the niche/ directory
Create a niche/ subfolder inside the free-design-tools directory:
2 Upload all 117 niche HTML files
Upload all .html files from the niche folder:
Important: Asset paths inside niche pages use ../assets/ (one level up). Make sure the assets/ folder is already uploaded at the free-design-tools level.
3 Verify niche pages load
Spot-check a few niche pages to confirm they work:
https://shops.beargrips.com/free-design-tools/niche/gym-apparel.htmlhttps://shops.beargrips.com/free-design-tools/niche/church-apparel.htmlhttps://shops.beargrips.com/free-design-tools/niche/pickleball-apparel.html- Logo + favicon loads on every page (from
../assets/) - Tool links point to
../background-remover.htmletc. (correct path) - CTA buttons link to
https://shops.beargrips.com - Check mobile responsiveness
4 Add all 117 niche pages to sitemap
Add all niche page URLs to sitemap.xml. Each gets priority 0.6:
Full list of URLs in the table above. All follow the same pattern.
5 Nginx — serve niche/ as static files
If nginx proxies everything to the Node app, add a location block for the niche directory:
This one block covers both the main tools pages AND the niche subdirectory.
Product Catalog — 85 SEO Pages
85 static HTML pages competing with Apliiq, Printify, and Printful for "custom [product] print on demand" keywords. All pages are pre-built with full SEO — just upload to the server.
What's Included
| Type | Count | Example URL |
|---|---|---|
| Catalog Hub | 1 | /products/index.html |
| Category Pages | 11 | /products/custom-t-shirts.html, /products/custom-hoodies.html |
| Brand Pages | 7 | /products/brands/bella-canvas.html, /products/brands/champion.html |
| Audience Pages | 3 | /products/womens.html, /products/mens.html, /products/youth.html |
| Product Pages | 63 | /products/products/airlume-cotton-athletic-tee.html |
| XML Sitemap | 1 | /products/sitemap-products.xml |
| Product Images | 85 | /products/images/*.png (Bear Grips proprietary) |
| Brand Logos | 6 | /products/images/brands/*.png |
SEO Features (Every Page)
- Unique title tags + meta descriptions targeting "custom [product] print on demand no minimum"
- BreadcrumbList schema (JSON-LD) on all pages
- Product schema (JSON-LD) on all 63 individual product pages
- FAQPage schema (JSON-LD) on hub page — 10 Q&As with crosslinks
- Open Graph + Twitter Card meta tags for social sharing
- Canonical URLs on every page
- Internal crosslinks between category, brand, audience, product, and free tools pages
- Print method section: DTG, DTF, Embroidery with product counts
- All-inclusive pricing messaging: "FREE Shipping + Printing Included + Unlimited Colors"
Deployment Steps
1 Create /products/ directory on server
Create the products directory structure on the DO server:
2 Upload all files from built-pages/catalog/
Upload the entire catalog build output to the server:
Total files: ~100 HTML + 85 images + 6 logos + assets + 1 XML sitemap
3 Nginx location block for /products/
Add this BEFORE the proxy_pass catch-all in the shops nginx config:
Then reload nginx:
4 Add product sitemap to robots.txt
Add the product catalog sitemap reference to robots.txt:
5 Verify pages load correctly
Test these URLs after deployment:
https://shops.beargrips.com/products/— Catalog hub with all categories, brands, featured productshttps://shops.beargrips.com/products/custom-t-shirts.html— Category pagehttps://shops.beargrips.com/products/brands/bella-canvas.html— Brand pagehttps://shops.beargrips.com/products/womens.html— Audience pagehttps://shops.beargrips.com/products/products/airlume-cotton-athletic-tee.html— Product pagehttps://shops.beargrips.com/products/sitemap-products.xml— XML sitemap- Verify: product images load, Bear Grips logo shows, "FREE Shipping" badges visible
- Verify: mobile responsive layout works
- Check View Source → JSON-LD schema present in <head>
6 Add internal link from shops homepage
Add a "Browse Catalog" or "Product Catalog" link somewhere visible on shops.beargrips.com homepage — nav bar, footer, or hero section. Link to:
This passes link equity from the homepage to all 85 catalog pages.
File Structure on Server
Programmatic SEO Pages (2,100+)
All pSEO pages are already live on Cloudflare Pages. No dev action needed for these — they're static HTML hosted separately.
Page Types & Counts
| Phase | Type | Pages | Example URL |
|---|---|---|---|
| 1 | Resource Pages (ideas, checklists, guides) | 354 | /resources/custom-gym-apparel-ideas.html |
| 2 | Competitor Comparisons | 35 | /comparisons/bear-grips-vs-printful.html |
| 3 | POD Glossary | 160 | /glossary/print-on-demand.html |
| 4 | Profit Calculator | 1 | /tools/profit-calculator.html |
| 5 | Affiliate / Side Hustle | 8 | /affiliate/best-pod-side-hustles-2026.html |
| 6 | Occasion / Seasonal | 17 | /occasions/fathers-day-custom-apparel.html |
| 7 | Vendor Spotlight Gallery | 8 | /vendors/gallery.html |
| 8 | Fundraising Content | 11 | /fundraising/church-fundraiser-apparel.html |
| 9 | Deals / Coupons | 1 | /deals/ |
| 10 | Niche Deep-Dives (sub-niches) | 620 | /tools/niche/boxing-gym-apparel.html |
| 11 | Product × Niche | 821 | /product-niche/hoodies-for-yoga-studio-apparel.html |
| 12 | How-To Guides | 118 | /how-to/how-to-start-a-gym-apparel-merch-business.html |
| TOTAL | 2,163+ |
What These Pages Do
- Target long-tail keywords — "custom yoga studio apparel ideas", "bear grips vs printful", "how to start a gym merch business"
- Drive organic traffic — each page targets a unique keyword with real content, not thin/duplicate
- Convert visitors — every page has CTAs to sign up at shops.beargrips.com
- Build authority — glossary, comparisons, and how-to guides establish Bear Grips as the category expert
Hosting Details
- Host: Cloudflare Pages (free tier, unlimited bandwidth)
- Project: bear-grips-pseo
- Source:
built-pages/directory in the repo - Architecture: Static HTML generated from JSON data files + Node.js generator scripts
- Sitemaps: Each phase has its own XML sitemap in its directory
Security Hardening
Pre-launch security checklist for shops.beargrips.com. Stripe handles real money, vendor accounts hold business data — this is not optional.
1. Stripe Payment Security
Stripe handles PCI compliance for card data, but your server-side integration must be airtight.
1 Webhook Signature Verification
Every Stripe webhook must be verified with stripe.webhooks.constructEvent() using your webhook signing secret. Without this, anyone can fake a payment/subscription event by sending a POST to your webhook endpoint.
2 Server-Side Price Validation
Never trust prices from the frontend. Always fetch product base prices from your database server-side when calculating orders. A malicious user can modify frontend JS to send $0 prices.
3 Stripe API Key Security
- Use restricted API keys with only the permissions your app needs (charges, subscriptions, customers)
- Store keys in
.env— never in source code or frontend JS - Publishable key (pk_live_) = safe for frontend. Secret key (sk_live_) = server only, NEVER exposed
- Rotate keys immediately if you suspect any exposure
4 Use Stripe Checkout or Elements
Never handle raw card numbers on your server. Use Stripe Checkout (hosted payment page) or Stripe Elements (embedded card form). Both keep card data on Stripe's servers — your server never touches it. This is required for PCI compliance.
2. Authentication & Session Security
1 Secure Session Cookies
Session tokens must use all three flags:
Never store session tokens in localStorage or sessionStorage — these are readable by any JS on the page, including injected scripts.
2 CSRF Protection
Add CSRF tokens to all state-changing forms and API endpoints (login, signup, plan changes, shop edits, Stripe actions). Libraries like csurf (Express) handle this.
3 Password Security
- Hash passwords with bcrypt (cost factor 12+) or argon2
- Never store plaintext, MD5, or SHA hashes
- Enforce minimum 8 characters
- Rate limit login: 5 failed attempts → 15 min lockout per IP + per account
4 Session Management
- Auto-logout after 30-60 minutes of inactivity
- Invalidate old sessions on password change
- Generate new session ID after login (prevent session fixation)
3. Server Security Headers (Nginx)
Add these headers to your Nginx server block for shops.beargrips.com. They prevent clickjacking, XSS, MIME sniffing, and enforce HTTPS.
4. DDoS & Bot Protection (Cloudflare)
Put Cloudflare in front of shops.beargrips.com. The free tier gives you instant DDoS protection, bot filtering, SSL, and CDN caching.
Setup Steps
- Create a free Cloudflare account at dash.cloudflare.com
- Add shops.beargrips.com → Cloudflare scans existing DNS records
- Update nameservers at GoDaddy to Cloudflare's (Cloudflare will tell you which ones)
- Enable "Under Attack Mode" if you ever see a spike in malicious traffic
- Turn on "Bot Fight Mode" in Security → Bots (free tier)
- Set SSL mode to "Full (strict)" since you already have Let's Encrypt certs
5. Rate Limiting on API Routes
Rate limit all API endpoints to prevent brute force and abuse. The directory app already has this pattern — apply it to shops.
6. Input Validation & Injection Prevention
SQL / NoSQL Injection
- Always use parameterized queries — never concatenate user input into database queries
- Use an ORM (Prisma, Sequelize, Mongoose) which parameterizes by default
- Validate and sanitize all inputs: vendor names, shop descriptions, product titles, profile fields
XSS (Cross-Site Scripting)
- React escapes HTML output by default — but never use
dangerouslySetInnerHTMLwith user content - Sanitize any user-generated content displayed on public pages (shop names, product descriptions)
- Use a library like
DOMPurifyif you must render HTML from user input
File Upload Security
If vendors upload logos or designs:
- Validate file type server-side (check magic bytes, not just extension)
- Enforce size limit: 5-10MB max
- Rename uploaded files (never use the original filename)
- Store uploads outside the web root or on a CDN (S3, Cloudflare R2)
- Never execute uploaded files — serve with
Content-Disposition: attachmentor proper MIME types
7. Data Protection
Environment Variables
- All API keys, DB credentials, Stripe keys, secrets in
.env— never committed to git - Verify
.gitignoreincludes:.env,.env.local,.env.production - Use different keys for development vs production
Database Backups
- Automated daily backups of all vendor data, orders, account info
- Store backups off-server (S3, Backblaze B2, or DO Spaces)
- Test restore process at least once before launch
- Set up weekly backup verification (restore to a test DB and confirm data integrity)
robots.txt — Block Sensitive Routes
8. Monitoring & Alerts
Error Logging
- Sentry (free tier) — catches frontend + backend errors with stack traces. Install:
npm install @sentry/node - Log all failed login attempts with IP and timestamp
- Log all Stripe webhook failures
- Never log sensitive data (passwords, card numbers, full API keys)
Uptime Monitoring
- UptimeRobot (free) — monitors shops.beargrips.com every 5 minutes, alerts on downtime via email/SMS
- Monitor both the homepage and at least one API endpoint
- Set up status page so vendors know if there's an outage
Quick Verification Checklist
After implementing, run these checks:
| # | Check | How to Test |
|---|---|---|
| 1 | HTTPS forced | Visit http://shops.beargrips.com — should redirect to https:// |
| 2 | Security headers | Run securityheaders.com — aim for A or A+ grade |
| 3 | Stripe webhooks verified | Send a test webhook from Stripe dashboard → confirm it's processed. Then send a fake POST to your webhook URL → confirm it's rejected |
| 4 | Rate limiting works | Hit /api/auth/login 6+ times rapidly → should get 429 on attempt 6 |
| 5 | XSS blocked | Try entering <script>alert(1)</script> as a shop name → should be escaped/rejected |
| 6 | No directory listing | Visit a directory URL like /api/ directly → should get 404/403, not a file listing |
| 7 | SSL cert valid | Run ssllabs.com/ssltest — aim for A grade |
| 8 | Sensitive routes blocked | Visit /admin/, /dashboard/ as logged-out user → should redirect to login, not show content |