diff --git a/.firebase/hosting.ZGlzdA.cache b/.firebase/hosting.ZGlzdA.cache
index 8f07c39..7a7d12a 100644
--- a/.firebase/hosting.ZGlzdA.cache
+++ b/.firebase/hosting.ZGlzdA.cache
@@ -1,31 +1,31 @@
-robots.txt,1784118671967,a9f80ec8139f358ccf245372fb028866625a4b0d19f44b3aadaeaa0ed1ff8e75
-tailtrails-logo.png,1784118671969,dc932ef86246fbf78221ba9128af50a6845890fcbf82101e83c67171d8c520c9
-placeholder.svg,1784118671967,e6d62457feaa2cf22a140b4ffae6cc1ec264e50991e369d61f901a3481f9229d
-index.html,1784118672031,3f11e47bff0a3720e2fb7f2221aa6d43e049fdd4d4173f8682f6b892be9e1df3
-app_store_button.svg,1784118671868,e163505e4516a4dad35281dc952f525f78907a21c49f95dba518a9d206ed45bf
-CNAME,1784118672117,dddc5976b778c369189842b7a4c661fb3088f02ceea7dc8d26565f179cd44f95
-raw-blogs/walking-your-dog-in-the-algarve-hidden-dangers-every-owner-should-know.md,1784118671967,fba3a0a9b8e8aee35b3300f86363b84e37ac5ab64ab4c3788a3dede919f781e6
-raw-blogs/the-importance-of-variety-in-your-dogs-life-and-how-to-do-it-right.md,1784118671967,b9120edf84aab42cea63f9cec38c9c86652b3d9fd8b869fd4c84e871e74050d3
-raw-blogs/top-10-hikes-to-do-with-your-dog-in-lagos-and-the-algarve.md,1784118671967,92dbf46e2d921d9366bb4ccfa4508a03867cfc6abd4c76d7c9ea576c86c158c7
-raw-blogs/how-to-give-a-reactive-dog-a-fulfilling-life-without-avoiding-the-world.md,1784118671967,cfaf693a02ce30c4453339a13bb7b45333803864c3ce3d4f42c75ec4a00572f5
-raw-blogs/off-leash-dog-rules-in-portugal-what-you-need-to-know-in-2026.md,1784118671967,7fbfcbe9b9b6f21837b322073f049857ca09935e07e568d42425c9ff3b15dfaf
-raw-blogs/how-to-choose-the-right-walk-for-your-dog-based-on-their-personality-and-needs.md,1784118671967,5c046464b0d04a334cd3c64b7571b2061d033ad3f3894dd0ff4065383e6ac41a
-raw-blogs/best-off-leash-areas-for-dogs-in-lagos-and-nearby.md,1784118671967,ba2e88fa252fc3bb096466b16e0abf91578415abdd4662b81efb324f257affe8
-404.html,1784118672123,3f11e47bff0a3720e2fb7f2221aa6d43e049fdd4d4173f8682f6b892be9e1df3
-assets/index-C8wIY7Lv.css,1784118672030,b5fc631c83de590f9ec0d6959f97ef138ef3556849cbada3dc9c0cb02d5f1619
-landing/sad-dog.avif,1784118671966,0d8926a6e4d1ec1f42318c6ee351f17766d57ba0c222c155f0f499753c8a779e
-landing/happy-dog.avif,1784118671966,71de609c9e5f4df9bab430649876c17de18696e808935691813da5e12cee8d6b
-IMG_2725.PNG,1784118671862,27b6d2b3d3f0639b27edde4a6e4dafd7ff30361b12ed532eea83ea9ff52cc57b
-assets/index-CCYERNNs.js,1784118672030,2b953d0955c6573dbd8656b0f8e6fa5b68bfe7d8c448e0045b25eb6bdf0632e1
-IMG_2722.PNG,1784118671856,5eb964eca487921be0a641ab01ef44a3a640bc33ee86ef8c78c47beb40c52212
-blog-images/troy-bridges-lbRNtUZPXXQ-unsplash.jpg,1784118671917,7cccb32745ffa54a51afdaf9b1ada36ecec8270ff64d57144f2e7936d3800b47
-IMG_2724.PNG,1784118671862,1a12277e84b449259e0553359d83de2506f3b85df4198c29d060549bbb5da1ba
-blog-images/rafaella-waasdorp-EkzMdwI_YE4-unsplash.jpg,1784118671904,4b06dd88c4b9ee1bb93193f4efefaf5222b45156991d65237580552dbd53a498
-blog-images/eric-ward-ISg37AI2A-s-unsplash.jpg,1784118671883,3fe77db2192fcbb773ae6700e784f576d2880d23f3de87675cca7df69e1d62de
-blog-images/jamie-street-m4BkRRprvP0-unsplash.jpg,1784118671894,102144b1e3ed572e2e614a7a30bad26d015306005d324e74a67f9391ac7b649d
-blog-images/joe-caione-qO-PIF84Vxg-unsplash.jpg,1784118671898,a818800a0777643571a2ac506ab2721e55314c5cc0805d2792fdca20c1f567ef
-blog-images/dagmar-klauzova-afBc-k2luH4-unsplash.jpg,1784118671881,a7ef47c2af03e7671ec94dded168d201559b5149c2cafe77b324cbc42f310ad5
-blog-images/afra-ramio-cp2HCVzguw4-unsplash.jpg,1784118671874,f5ba745a987168b658a9091041de9bc4ebdbc2e43a6f1f2574c543dc2ed4113c
-blog-images/tatum-bergen-Vt3odrTM4cQ-unsplash.jpg,1784118671911,805d069b8cdaa4a18a655f10f6059cc54609c5f568d7c7ea374f19840776d044
-IMG_2721.PNG,1784118671856,80bf0292743b93e52e260ea32a347ba5189b6ebcdcf26307c9ec098546dd1b61
-hero.mp4,1784118671955,68cf98422d073512761ac7c4a0aa9b11e88b71381c1874422048a578c344af92
+index.html,1787241043042,23ab785dcf609ba3797371f540ebbf0da174d23662bda7a91e7d7e5a5129b9f7
+robots.txt,1787241042983,a9f80ec8139f358ccf245372fb028866625a4b0d19f44b3aadaeaa0ed1ff8e75
+tailtrails-logo.png,1787241042983,dc932ef86246fbf78221ba9128af50a6845890fcbf82101e83c67171d8c520c9
+app_store_button.svg,1787241042903,e163505e4516a4dad35281dc952f525f78907a21c49f95dba518a9d206ed45bf
+placeholder.svg,1787241042982,e6d62457feaa2cf22a140b4ffae6cc1ec264e50991e369d61f901a3481f9229d
+404.html,1787241043108,23ab785dcf609ba3797371f540ebbf0da174d23662bda7a91e7d7e5a5129b9f7
+CNAME,1787241043103,dddc5976b778c369189842b7a4c661fb3088f02ceea7dc8d26565f179cd44f95
+raw-blogs/walking-your-dog-in-the-algarve-hidden-dangers-every-owner-should-know.md,1787241042983,fba3a0a9b8e8aee35b3300f86363b84e37ac5ab64ab4c3788a3dede919f781e6
+raw-blogs/top-10-hikes-to-do-with-your-dog-in-lagos-and-the-algarve.md,1787241042982,92dbf46e2d921d9366bb4ccfa4508a03867cfc6abd4c76d7c9ea576c86c158c7
+raw-blogs/best-off-leash-areas-for-dogs-in-lagos-and-nearby.md,1787241042982,ba2e88fa252fc3bb096466b16e0abf91578415abdd4662b81efb324f257affe8
+raw-blogs/off-leash-dog-rules-in-portugal-what-you-need-to-know-in-2026.md,1787241042982,7fbfcbe9b9b6f21837b322073f049857ca09935e07e568d42425c9ff3b15dfaf
+raw-blogs/the-importance-of-variety-in-your-dogs-life-and-how-to-do-it-right.md,1787241042982,b9120edf84aab42cea63f9cec38c9c86652b3d9fd8b869fd4c84e871e74050d3
+raw-blogs/how-to-choose-the-right-walk-for-your-dog-based-on-their-personality-and-needs.md,1787241042982,5c046464b0d04a334cd3c64b7571b2061d033ad3f3894dd0ff4065383e6ac41a
+raw-blogs/how-to-give-a-reactive-dog-a-fulfilling-life-without-avoiding-the-world.md,1787241042982,cfaf693a02ce30c4453339a13bb7b45333803864c3ce3d4f42c75ec4a00572f5
+assets/index-CU78BVRf.css,1787241043042,7c88342b634dcb962b09e80964ec25efb0417b3b84a9ea4d94a370b59e5ad4d0
+landing/sad-dog.avif,1787241042982,0d8926a6e4d1ec1f42318c6ee351f17766d57ba0c222c155f0f499753c8a779e
+landing/happy-dog.avif,1787241042978,71de609c9e5f4df9bab430649876c17de18696e808935691813da5e12cee8d6b
+IMG_2725.PNG,1787241042899,27b6d2b3d3f0639b27edde4a6e4dafd7ff30361b12ed532eea83ea9ff52cc57b
+assets/index-DmqQSK7M.js,1787241043042,c4e28b173525e94180d05b2f9b60f031ecb761ab9597cfa49a92763375f6f1bc
+IMG_2722.PNG,1787241042891,5eb964eca487921be0a641ab01ef44a3a640bc33ee86ef8c78c47beb40c52212
+blog-images/troy-bridges-lbRNtUZPXXQ-unsplash.jpg,1787241042945,7cccb32745ffa54a51afdaf9b1ada36ecec8270ff64d57144f2e7936d3800b47
+IMG_2724.PNG,1787241042899,1a12277e84b449259e0553359d83de2506f3b85df4198c29d060549bbb5da1ba
+blog-images/rafaella-waasdorp-EkzMdwI_YE4-unsplash.jpg,1787241042935,4b06dd88c4b9ee1bb93193f4efefaf5222b45156991d65237580552dbd53a498
+blog-images/eric-ward-ISg37AI2A-s-unsplash.jpg,1787241042920,3fe77db2192fcbb773ae6700e784f576d2880d23f3de87675cca7df69e1d62de
+blog-images/jamie-street-m4BkRRprvP0-unsplash.jpg,1787241042925,102144b1e3ed572e2e614a7a30bad26d015306005d324e74a67f9391ac7b649d
+blog-images/joe-caione-qO-PIF84Vxg-unsplash.jpg,1787241042930,a818800a0777643571a2ac506ab2721e55314c5cc0805d2792fdca20c1f567ef
+blog-images/dagmar-klauzova-afBc-k2luH4-unsplash.jpg,1787241042914,a7ef47c2af03e7671ec94dded168d201559b5149c2cafe77b324cbc42f310ad5
+blog-images/afra-ramio-cp2HCVzguw4-unsplash.jpg,1787241042907,f5ba745a987168b658a9091041de9bc4ebdbc2e43a6f1f2574c543dc2ed4113c
+blog-images/tatum-bergen-Vt3odrTM4cQ-unsplash.jpg,1787241042938,805d069b8cdaa4a18a655f10f6059cc54609c5f568d7c7ea374f19840776d044
+IMG_2721.PNG,1787241042890,80bf0292743b93e52e260ea32a347ba5189b6ebcdcf26307c9ec098546dd1b61
+hero.mp4,1787241042966,68cf98422d073512761ac7c4a0aa9b11e88b71381c1874422048a578c344af92
diff --git a/package-lock.json b/package-lock.json
index fe8608c..c7f620d 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -14,7 +14,6 @@
"class-variance-authority": "0.7.1",
"clsx": "2.1.1",
"lucide-react": "^0.577.0",
- "marked": "^18.0.2",
"motion": "^12.23.24",
"react": "^19.2.4",
"react-dom": "^19.2.4",
@@ -27,6 +26,7 @@
"@types/react-dom": "^19.2.3",
"autoprefixer": "^10.4.27",
"gh-pages": "^6.3.0",
+ "puppeteer": "^25.8.0",
"tailwindcss": "^4.2.2",
"tsx": "^4.21.0",
"typescript": "~5.8.2",
@@ -588,6 +588,35 @@
"url": "https://github.com/sponsors/Boshen"
}
},
+ "node_modules/@puppeteer/browsers": {
+ "version": "3.2.1",
+ "resolved": "https://registry.npmjs.org/@puppeteer/browsers/-/browsers-3.2.1.tgz",
+ "integrity": "sha512-KDz+3qDRdBAlRlMjmKyj6dEs33YHTk/xRHEENSXq6TNnhgoU15ruSHtEBeVF6OZ9tBDY55Se4P0nFMNsipzU9A==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "modern-tar": "^0.8.0",
+ "yargs": "^18.0.0"
+ },
+ "bin": {
+ "browsers": "lib/main-cli.js"
+ },
+ "engines": {
+ "node": ">=22.12.0"
+ },
+ "peerDependencies": {
+ "proxy-agent": ">=8.0.1",
+ "yauzl": "^2.10.0 || ^3.4.0"
+ },
+ "peerDependenciesMeta": {
+ "proxy-agent": {
+ "optional": true
+ },
+ "yauzl": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@radix-ui/primitive": {
"version": "1.1.3",
"resolved": "https://registry.npmjs.org/@radix-ui/primitive/-/primitive-1.1.3.tgz",
@@ -1421,17 +1450,6 @@
"tslib": "^2.4.0"
}
},
- "node_modules/@types/node": {
- "version": "22.19.15",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-22.19.15.tgz",
- "integrity": "sha512-F0R/h2+dsy5wJAUe3tAU6oqa2qbWY5TpNfL/RGmo1y38hiyO1w3x2jPtt76wmuaJI4DQnOBu21cNXQ2STIUUWg==",
- "license": "MIT",
- "optional": true,
- "peer": true,
- "dependencies": {
- "undici-types": "~6.21.0"
- }
- },
"node_modules/@types/react": {
"version": "19.2.14",
"resolved": "https://registry.npmjs.org/@types/react/-/react-19.2.14.tgz",
@@ -1477,6 +1495,32 @@
}
}
},
+ "node_modules/ansi-regex": {
+ "version": "6.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.3.0.tgz",
+ "integrity": "sha512-WpDfL7NO6j7tH88IDBNVdUJxDh9nmCteAVW9dsep846XdwF4naCBK+/tGLX3KJgcpgMRXCFlTM2hKGoK9FsdrQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-regex?sponsor=1"
+ }
+ },
+ "node_modules/ansi-styles": {
+ "version": "6.2.3",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.3.tgz",
+ "integrity": "sha512-4Dj6M28JB+oAH8kFkTLUo+a2jwOFkuqb3yucU0CANcRRUbxS0cP0nZYCGjcc3BNXwRIsUVmDGgzawme7zvJHvg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
"node_modules/array-union": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz",
@@ -1612,6 +1656,23 @@
],
"license": "CC-BY-4.0"
},
+ "node_modules/chromium-bidi": {
+ "version": "17.0.2",
+ "resolved": "https://registry.npmjs.org/chromium-bidi/-/chromium-bidi-17.0.2.tgz",
+ "integrity": "sha512-5v9GQFhTktFvotn/OFNJBmKLKRAb6n9r0bVCwf7sHgWc3/JryK0bj1nn93L3pHFrfgcsu6Be6EWsDi+1XHTGDg==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "mitt": "^3.0.1",
+ "zod": "^3.24.1"
+ },
+ "engines": {
+ "node": ">=20.19.0 <22.0.0 || >=22.12.0"
+ },
+ "peerDependencies": {
+ "devtools-protocol": "*"
+ }
+ },
"node_modules/class-variance-authority": {
"version": "0.7.1",
"resolved": "https://registry.npmjs.org/class-variance-authority/-/class-variance-authority-0.7.1.tgz",
@@ -1624,6 +1685,39 @@
"url": "https://polar.sh/cva"
}
},
+ "node_modules/cliui": {
+ "version": "9.0.1",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-9.0.1.tgz",
+ "integrity": "sha512-k7ndgKhwoQveBL+/1tqGJYNz097I7WOvwbmmU2AR5+magtbjPWQTS1C5vzGkBC8Ym8UWRzfKUzUUqFLypY4Q+w==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "string-width": "^7.2.0",
+ "strip-ansi": "^7.1.0",
+ "wrap-ansi": "^9.0.0"
+ },
+ "engines": {
+ "node": ">=20"
+ }
+ },
+ "node_modules/cliui/node_modules/string-width": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz",
+ "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "emoji-regex": "^10.3.0",
+ "get-east-asian-width": "^1.0.0",
+ "strip-ansi": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/clsx": {
"version": "2.1.1",
"resolved": "https://registry.npmjs.org/clsx/-/clsx-2.1.1.tgz",
@@ -1679,6 +1773,13 @@
"node": ">=8"
}
},
+ "node_modules/devtools-protocol": {
+ "version": "0.0.1666840",
+ "resolved": "https://registry.npmjs.org/devtools-protocol/-/devtools-protocol-0.0.1666840.tgz",
+ "integrity": "sha512-gCcO42XCHKEs7Ag0S7aGYsnJ7hlgrO3qderYqeiY0Eqk+0GFfuvT13IA0hHreJTa2KCdDVyGMeOhdMNmrrTjVg==",
+ "dev": true,
+ "license": "BSD-3-Clause"
+ },
"node_modules/dir-glob": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz",
@@ -1706,6 +1807,13 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/emoji-regex": {
+ "version": "10.6.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.6.0.tgz",
+ "integrity": "sha512-toUI84YS5YmxW219erniWD0CIVOo46xGKColeNQRgOzDorgBi1v4D71/OFzgD9GO2UGKIv1C3Sp8DAn0+j5w7A==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/enhanced-resolve": {
"version": "5.20.1",
"resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.20.1.tgz",
@@ -1951,6 +2059,29 @@
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
+ "node_modules/get-caller-file": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": "6.* || 8.* || >= 10.*"
+ }
+ },
+ "node_modules/get-east-asian-width": {
+ "version": "1.6.0",
+ "resolved": "https://registry.npmjs.org/get-east-asian-width/-/get-east-asian-width-1.6.0.tgz",
+ "integrity": "sha512-QRbvDIbx6YklUe6RxeTeleMR0yv3cYH6PsPZHcnVn7xv7zO1BHN8r0XETu8n6Ye3Q+ahtSarc3WgtNWmehIBfA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
"node_modules/get-tsconfig": {
"version": "4.13.6",
"resolved": "https://registry.npmjs.org/get-tsconfig/-/get-tsconfig-4.13.6.tgz",
@@ -2341,6 +2472,19 @@
"url": "https://opencollective.com/parcel"
}
},
+ "node_modules/lilconfig": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/lilconfig/-/lilconfig-3.1.3.tgz",
+ "integrity": "sha512-/vlFKAoH5Cgt3Ie+JLhRbwOsCQePABiU3tJ1egGvyQ+33R/vcwM2Zl2QR/LzjsBeItPt3oSVXapn+m4nQDvpzw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=14"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/antonk52"
+ }
+ },
"node_modules/locate-path": {
"version": "5.0.0",
"resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz",
@@ -2388,18 +2532,6 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
- "node_modules/marked": {
- "version": "18.0.2",
- "resolved": "https://registry.npmjs.org/marked/-/marked-18.0.2.tgz",
- "integrity": "sha512-NsmlUYBS/Zg57rgDWMYdnre6OTj4e+qq/JS2ot3KrYLSoHLw+sDu0Nm1ZGpRgYAq6c+b1ekaY5NzVchMCQnzcg==",
- "license": "MIT",
- "bin": {
- "marked": "bin/marked.js"
- },
- "engines": {
- "node": ">= 20"
- }
- },
"node_modules/merge2": {
"version": "1.4.1",
"resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz",
@@ -2424,6 +2556,23 @@
"node": ">=8.6"
}
},
+ "node_modules/mitt": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/mitt/-/mitt-3.0.1.tgz",
+ "integrity": "sha512-vKivATfr97l2/QBCYAkXYDbrIWPM2IIKEl7YPhjCvKlG3kE2gm+uBo6nEXK3M5/Ffh/FLpKExzOQ3JJoJGFKBw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/modern-tar": {
+ "version": "0.8.4",
+ "resolved": "https://registry.npmjs.org/modern-tar/-/modern-tar-0.8.4.tgz",
+ "integrity": "sha512-gN54ddmyzEg10orwZ2u4OOv+bjpMWdIl5jIkodK97bMq8QBSL5c0D7YX0lT1Ooz+99S7+PvFbnxzdjgHo1r41g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18.0.0"
+ }
+ },
"node_modules/motion": {
"version": "12.38.0",
"resolved": "https://registry.npmjs.org/motion/-/motion-12.38.0.tgz",
@@ -2616,6 +2765,46 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/puppeteer": {
+ "version": "25.8.0",
+ "resolved": "https://registry.npmjs.org/puppeteer/-/puppeteer-25.8.0.tgz",
+ "integrity": "sha512-3gcUJ+Jfodb5zNa/lWLZukBUwYiRIwAc8WRICoqfi+ZYmNWqpsPFyanTU3Gw/lhgII9aotVbAmhT6/NKHWgyUA==",
+ "dev": true,
+ "hasInstallScript": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@puppeteer/browsers": "3.2.1",
+ "chromium-bidi": "17.0.2",
+ "devtools-protocol": "0.0.1666840",
+ "lilconfig": "^3.1.3",
+ "puppeteer-core": "25.8.0",
+ "typed-query-selector": "^2.12.2"
+ },
+ "bin": {
+ "puppeteer": "lib/puppeteer/node/cli.js"
+ },
+ "engines": {
+ "node": ">=22.12.0"
+ }
+ },
+ "node_modules/puppeteer-core": {
+ "version": "25.8.0",
+ "resolved": "https://registry.npmjs.org/puppeteer-core/-/puppeteer-core-25.8.0.tgz",
+ "integrity": "sha512-LDOrawV8vfCVk+yLj2ozvajNP4Sv3OV9y3Tpiyy2g2Z+aQlbcozP6KJfI4iSBq7YQER+86ihEtPa5ioiZyWxMQ==",
+ "dev": true,
+ "license": "Apache-2.0",
+ "dependencies": {
+ "@puppeteer/browsers": "3.2.1",
+ "chromium-bidi": "17.0.2",
+ "devtools-protocol": "0.0.1666840",
+ "typed-query-selector": "^2.12.2",
+ "webdriver-bidi-protocol": "0.4.2",
+ "ws": "^8.21.1"
+ },
+ "engines": {
+ "node": ">=22.12.0"
+ }
+ },
"node_modules/queue-microtask": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz",
@@ -2840,6 +3029,39 @@
"node": ">=0.10.0"
}
},
+ "node_modules/string-width": {
+ "version": "8.2.2",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-8.2.2.tgz",
+ "integrity": "sha512-GaPUh5gfdrYzqeVNZvUfT23vYYxXzKYidUcnMtJg/3rxRV63EFZy3k6xfKlmfeJD0176lnUV/Usr3XcwSvFzpg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "get-east-asian-width": "^1.5.0",
+ "strip-ansi": "^7.1.2"
+ },
+ "engines": {
+ "node": ">=20"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/strip-ansi": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.2.0.tgz",
+ "integrity": "sha512-yDPMNjp4WyfYBkHnjIRLfca1i6KMyGCtsVgoKe/z1+6vukgaENdgGBZt+ZmKPc4gavvEZ5OgHfHdrazhgNyG7w==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^6.2.2"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/strip-ansi?sponsor=1"
+ }
+ },
"node_modules/strip-outer": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz",
@@ -2979,6 +3201,13 @@
"fsevents": "~2.3.3"
}
},
+ "node_modules/typed-query-selector": {
+ "version": "2.12.2",
+ "resolved": "https://registry.npmjs.org/typed-query-selector/-/typed-query-selector-2.12.2.tgz",
+ "integrity": "sha512-EOPFbyIub4ngnEdqi2yOcNeDLaX/0jcE1JoAXQDDMIthap7FoN795lc/SHfIq2d416VufXpM8z/lD+WRm2gfOQ==",
+ "dev": true,
+ "license": "MIT"
+ },
"node_modules/typescript": {
"version": "5.8.3",
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.8.3.tgz",
@@ -2993,14 +3222,6 @@
"node": ">=14.17"
}
},
- "node_modules/undici-types": {
- "version": "6.21.0",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.21.0.tgz",
- "integrity": "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ==",
- "license": "MIT",
- "optional": true,
- "peer": true
- },
"node_modules/universalify": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz",
@@ -3130,6 +3351,119 @@
"funding": {
"url": "https://github.com/sponsors/jonschlinkert"
}
+ },
+ "node_modules/webdriver-bidi-protocol": {
+ "version": "0.4.2",
+ "resolved": "https://registry.npmjs.org/webdriver-bidi-protocol/-/webdriver-bidi-protocol-0.4.2.tgz",
+ "integrity": "sha512-VSV+fzfChirL3e7jay2yUC7B4HQCGtEWEg/MSSQbK+qWbqeGlRLlXTzPpYr3XGUvbpDHumWZBJxgesg4N7dbtA==",
+ "dev": true,
+ "license": "Apache-2.0"
+ },
+ "node_modules/wrap-ansi": {
+ "version": "9.0.2",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-9.0.2.tgz",
+ "integrity": "sha512-42AtmgqjV+X1VpdOfyTGOYRi0/zsoLqtXQckTmqTeybT+BDIbM/Guxo7x3pE2vtpr1ok6xRqM9OpBe+Jyoqyww==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^6.2.1",
+ "string-width": "^7.0.0",
+ "strip-ansi": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+ }
+ },
+ "node_modules/wrap-ansi/node_modules/string-width": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-7.2.0.tgz",
+ "integrity": "sha512-tsaTIkKW9b4N+AEj+SVA+WhJzV7/zMhcSu78mLKWSk7cXMOSHsBKFWUs0fWwq8QyK3MgJBQRX6Gbi4kYbdvGkQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "emoji-regex": "^10.3.0",
+ "get-east-asian-width": "^1.0.0",
+ "strip-ansi": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/ws": {
+ "version": "8.21.3",
+ "resolved": "https://registry.npmjs.org/ws/-/ws-8.21.3.tgz",
+ "integrity": "sha512-201TZ/kPWxoPr/OKWjquZR1SWKXcvxdH+e1xrx89b3YbmzLMFCLfnaG1HFIgWzJOEWZ7MvpK++odZufgYR50Rw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=10.0.0"
+ },
+ "peerDependencies": {
+ "bufferutil": "^4.0.1",
+ "utf-8-validate": ">=5.0.2"
+ },
+ "peerDependenciesMeta": {
+ "bufferutil": {
+ "optional": true
+ },
+ "utf-8-validate": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/y18n": {
+ "version": "5.0.8",
+ "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz",
+ "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/yargs": {
+ "version": "18.1.0",
+ "resolved": "https://registry.npmjs.org/yargs/-/yargs-18.1.0.tgz",
+ "integrity": "sha512-2rAgRKu54VsHkqI0/tYkmluGXHD4KW7yZoycuqDQ15QOTnc2VVfy0nN/1eMhnQLO00A+dwtK20xuCnc1YGeUyg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "cliui": "^9.0.1",
+ "escalade": "^3.1.1",
+ "get-caller-file": "^2.0.5",
+ "string-width": "^8.2.1",
+ "y18n": "^5.0.5",
+ "yargs-parser": "^22.0.0"
+ },
+ "engines": {
+ "node": "^20.19.0 || ^22.12.0 || >=23"
+ }
+ },
+ "node_modules/yargs-parser": {
+ "version": "22.0.0",
+ "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-22.0.0.tgz",
+ "integrity": "sha512-rwu/ClNdSMpkSrUb+d6BRsSkLUq1fmfsY6TOpYzTwvwkg1/NRG85KBy3kq++A8LKQwX6lsu+aWad+2khvuXrqw==",
+ "dev": true,
+ "license": "ISC",
+ "engines": {
+ "node": "^20.19.0 || ^22.12.0 || >=23"
+ }
+ },
+ "node_modules/zod": {
+ "version": "3.25.76",
+ "resolved": "https://registry.npmjs.org/zod/-/zod-3.25.76.tgz",
+ "integrity": "sha512-gzUt/qt81nXsFGKIFcC3YnfEAx5NkunCfnDlvuBSSFS02bcXu4Lmea0AFIUwbLWxWPx3d9p8S5QoaujKcNQxcQ==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/colinhacks"
+ }
}
}
}
diff --git a/package.json b/package.json
index a907804..efadb1b 100644
--- a/package.json
+++ b/package.json
@@ -5,7 +5,7 @@
"type": "module",
"scripts": {
"dev": "vite",
- "build": "vite build",
+ "build": "node scripts/generate-sitemap.mjs && vite build && node scripts/prerender.mjs && node scripts/postbuild.cjs",
"postbuild": "node ./scripts/postbuild.cjs",
"predeploy": "npm run build",
"deploy": "gh-pages -d dist",
@@ -20,7 +20,6 @@
"class-variance-authority": "0.7.1",
"clsx": "2.1.1",
"lucide-react": "^0.577.0",
- "marked": "^18.0.2",
"motion": "^12.23.24",
"react": "^19.2.4",
"react-dom": "^19.2.4",
@@ -33,6 +32,7 @@
"@types/react-dom": "^19.2.3",
"autoprefixer": "^10.4.27",
"gh-pages": "^6.3.0",
+ "puppeteer": "^25.8.0",
"tailwindcss": "^4.2.2",
"tsx": "^4.21.0",
"typescript": "~5.8.2",
diff --git a/public/IMG_2721.PNG b/public/IMG_2721.PNG
deleted file mode 100644
index 045438e..0000000
Binary files a/public/IMG_2721.PNG and /dev/null differ
diff --git a/public/IMG_2721.webp b/public/IMG_2721.webp
new file mode 100644
index 0000000..4275e33
Binary files /dev/null and b/public/IMG_2721.webp differ
diff --git a/public/IMG_2722.PNG b/public/IMG_2722.PNG
deleted file mode 100644
index bc986d8..0000000
Binary files a/public/IMG_2722.PNG and /dev/null differ
diff --git a/public/IMG_2722.webp b/public/IMG_2722.webp
new file mode 100644
index 0000000..90b998e
Binary files /dev/null and b/public/IMG_2722.webp differ
diff --git a/public/IMG_2724.PNG b/public/IMG_2724.PNG
deleted file mode 100644
index 17b0de1..0000000
Binary files a/public/IMG_2724.PNG and /dev/null differ
diff --git a/public/IMG_2724.webp b/public/IMG_2724.webp
new file mode 100644
index 0000000..0d18ab1
Binary files /dev/null and b/public/IMG_2724.webp differ
diff --git a/public/IMG_2725.PNG b/public/IMG_2725.PNG
deleted file mode 100644
index 58dec14..0000000
Binary files a/public/IMG_2725.PNG and /dev/null differ
diff --git a/public/IMG_2725.webp b/public/IMG_2725.webp
new file mode 100644
index 0000000..58449f5
Binary files /dev/null and b/public/IMG_2725.webp differ
diff --git a/public/blog-images/afra-ramio-cp2HCVzguw4-unsplash.jpg b/public/blog-images/afra-ramio-cp2HCVzguw4-unsplash.jpg
deleted file mode 100644
index 0a06ac4..0000000
Binary files a/public/blog-images/afra-ramio-cp2HCVzguw4-unsplash.jpg and /dev/null differ
diff --git a/public/blog-images/best-off-leash-areas-for-dogs-in-lagos-and-nearby.webp b/public/blog-images/best-off-leash-areas-for-dogs-in-lagos-and-nearby.webp
new file mode 100644
index 0000000..b840188
Binary files /dev/null and b/public/blog-images/best-off-leash-areas-for-dogs-in-lagos-and-nearby.webp differ
diff --git a/public/blog-images/dagmar-klauzova-afBc-k2luH4-unsplash.jpg b/public/blog-images/dagmar-klauzova-afBc-k2luH4-unsplash.jpg
deleted file mode 100644
index efd3c89..0000000
Binary files a/public/blog-images/dagmar-klauzova-afBc-k2luH4-unsplash.jpg and /dev/null differ
diff --git a/public/blog-images/eric-ward-ISg37AI2A-s-unsplash.jpg b/public/blog-images/eric-ward-ISg37AI2A-s-unsplash.jpg
deleted file mode 100644
index 3df44a8..0000000
Binary files a/public/blog-images/eric-ward-ISg37AI2A-s-unsplash.jpg and /dev/null differ
diff --git a/public/blog-images/how-to-choose-the-right-walk-for-your-dog-based-on-their-personality-and-needs.webp b/public/blog-images/how-to-choose-the-right-walk-for-your-dog-based-on-their-personality-and-needs.webp
new file mode 100644
index 0000000..701b769
Binary files /dev/null and b/public/blog-images/how-to-choose-the-right-walk-for-your-dog-based-on-their-personality-and-needs.webp differ
diff --git a/public/blog-images/how-to-give-a-reactive-dog-a-fulfilling-life-without-avoiding-the-world.webp b/public/blog-images/how-to-give-a-reactive-dog-a-fulfilling-life-without-avoiding-the-world.webp
new file mode 100644
index 0000000..d506603
Binary files /dev/null and b/public/blog-images/how-to-give-a-reactive-dog-a-fulfilling-life-without-avoiding-the-world.webp differ
diff --git a/public/blog-images/jamie-street-m4BkRRprvP0-unsplash.jpg b/public/blog-images/jamie-street-m4BkRRprvP0-unsplash.jpg
deleted file mode 100644
index df34267..0000000
Binary files a/public/blog-images/jamie-street-m4BkRRprvP0-unsplash.jpg and /dev/null differ
diff --git a/public/blog-images/joe-caione-qO-PIF84Vxg-unsplash.jpg b/public/blog-images/joe-caione-qO-PIF84Vxg-unsplash.jpg
deleted file mode 100644
index b820c72..0000000
Binary files a/public/blog-images/joe-caione-qO-PIF84Vxg-unsplash.jpg and /dev/null differ
diff --git a/public/blog-images/off-leash-dog-rules-in-portugal-what-you-need-to-know-in-2026.webp b/public/blog-images/off-leash-dog-rules-in-portugal-what-you-need-to-know-in-2026.webp
new file mode 100644
index 0000000..3de059e
Binary files /dev/null and b/public/blog-images/off-leash-dog-rules-in-portugal-what-you-need-to-know-in-2026.webp differ
diff --git a/public/blog-images/rafaella-waasdorp-EkzMdwI_YE4-unsplash.jpg b/public/blog-images/rafaella-waasdorp-EkzMdwI_YE4-unsplash.jpg
deleted file mode 100644
index 306fb42..0000000
Binary files a/public/blog-images/rafaella-waasdorp-EkzMdwI_YE4-unsplash.jpg and /dev/null differ
diff --git a/public/blog-images/tatum-bergen-Vt3odrTM4cQ-unsplash.jpg b/public/blog-images/tatum-bergen-Vt3odrTM4cQ-unsplash.jpg
deleted file mode 100644
index a96e735..0000000
Binary files a/public/blog-images/tatum-bergen-Vt3odrTM4cQ-unsplash.jpg and /dev/null differ
diff --git a/public/blog-images/the-importance-of-variety-in-your-dogs-life-and-how-to-do-it-right.webp b/public/blog-images/the-importance-of-variety-in-your-dogs-life-and-how-to-do-it-right.webp
new file mode 100644
index 0000000..e37c1d7
Binary files /dev/null and b/public/blog-images/the-importance-of-variety-in-your-dogs-life-and-how-to-do-it-right.webp differ
diff --git a/public/blog-images/top-10-hikes-to-do-with-your-dog-in-lagos-and-the-algarve.webp b/public/blog-images/top-10-hikes-to-do-with-your-dog-in-lagos-and-the-algarve.webp
new file mode 100644
index 0000000..1c97d41
Binary files /dev/null and b/public/blog-images/top-10-hikes-to-do-with-your-dog-in-lagos-and-the-algarve.webp differ
diff --git a/public/blog-images/troy-bridges-lbRNtUZPXXQ-unsplash.jpg b/public/blog-images/troy-bridges-lbRNtUZPXXQ-unsplash.jpg
deleted file mode 100644
index fa1ee2d..0000000
Binary files a/public/blog-images/troy-bridges-lbRNtUZPXXQ-unsplash.jpg and /dev/null differ
diff --git a/public/blog-images/walking-your-dog-in-the-algarve-hidden-dangers-every-owner-should-know.webp b/public/blog-images/walking-your-dog-in-the-algarve-hidden-dangers-every-owner-should-know.webp
new file mode 100644
index 0000000..5edacbd
Binary files /dev/null and b/public/blog-images/walking-your-dog-in-the-algarve-hidden-dangers-every-owner-should-know.webp differ
diff --git a/public/hero.mp4 b/public/hero.mp4
deleted file mode 100644
index 1f40c10..0000000
Binary files a/public/hero.mp4 and /dev/null differ
diff --git a/public/raw-blogs/best-off-leash-areas-for-dogs-in-lagos-and-nearby.md b/public/raw-blogs/best-off-leash-areas-for-dogs-in-lagos-and-nearby.md
deleted file mode 100644
index fdb56b7..0000000
--- a/public/raw-blogs/best-off-leash-areas-for-dogs-in-lagos-and-nearby.md
+++ /dev/null
@@ -1,126 +0,0 @@
-### **Introduction**
-
-Finding a good place to let your dog off-leash in Lagos isn’t always straightforward.
-
-Some areas are:
-
-* Too busy
-* Too unpredictable
-* Or not actually suitable for your dog
-
-But when you find the right spot, it changes everything.
-
-Here are some of the best off-leash-friendly areas around Lagos, and how to choose the right one for your dog.
-
----
-
-## **1. Mata Nacional de Barão de São João**
-
-**Best for:** Most dogs
- **Why it works:**
-
-* Wide, open forest trails
-* Plenty of space to create distance
-* Shaded and cooler
-
-Ideal for dogs who need **space without isolation**
-
----
-
-## **2. Praia da Bordeira (West Coast)**
-
-**Best for:** High-energy dogs
- **Why it works:**
-
-* Huge open beach
-* Low crowd density (outside peak times)
-* Great for running
-
- Watch:
-
-* Wind exposure
-* Seasonal rules
-
----
-
-## **3. Ria de Alvor (Quiet Sections)**
-
-**Best for:** Lower-energy or calm dogs
- **Why it works:**
-
-* Flat terrain
-* Open visibility
-
-Avoid peak hours, it can get busy
-
----
-
-## **4. Monchique Countryside**
-
-**Best for:** Dogs needing low stimulation
- **Why it works:**
-
-* Quiet
-* Natural
-* Cooler temperatures
-
-Great for reactive or sensitive dogs
-
----
-
-## **5. Local Countryside Trails (Hidden Gems)**
-
-Often overlooked, but some of the best options.
-
-These areas offer:
-
-* Lower dog traffic
-* More control
-* Flexible space
-
-Especially useful for:
-
-* Training recall
-* Building confidence
-
-
-Check out trails near countryside villages like Bensafrim and Vila do Bispo.
-
----
-
-## **Important: Not Every “Off-Leash Area” Is Right**
-
-Just because a place allows off-leash doesn’t mean it’s suitable.
-
-Before letting your dog off:
-
-* Check the environment
-* Look at dog traffic
-* Consider your dog’s behaviour
-
----
-
-## **What Makes a Good Off-Leash Spot?**
-
-The best places have:
-
-* Space to move freely
-* Clear visibility
-* Low unpredictability
-* An environment suited to your dog
-
----
-
-## **Final Thoughts**
-
-The goal isn’t just to let your dog off-leash.
-
-It’s to do it in a way that:
-
-* Feels safe
-* Feels calm
-* And actually benefits your dog
-
-Because the right environment makes all the difference.
-
-
diff --git a/public/raw-blogs/how-to-choose-the-right-walk-for-your-dog-based-on-their-personality-and-needs.md b/public/raw-blogs/how-to-choose-the-right-walk-for-your-dog-based-on-their-personality-and-needs.md
deleted file mode 100644
index 8498188..0000000
--- a/public/raw-blogs/how-to-choose-the-right-walk-for-your-dog-based-on-their-personality-and-needs.md
+++ /dev/null
@@ -1,131 +0,0 @@
-### **Introduction**
-
-Choosing a walk for your dog often comes down to convenience.
-
-What’s nearby.
-What you’ve done before.
-What seems “good enough.”
-
-But the best walks aren’t chosen that way.
-
-They’re chosen based on **your dog**.
-
----
-
-### **Step 1: Understand Your Dog’s Profile**
-
-Start with the basics:
-
-* Energy level (low, medium, high)
-* Sociability (loves dogs vs prefers space)
-* Confidence (bold vs cautious)
-* Sensitivities (noise, movement, crowds)
-* Physical needs (age, injuries, endurance)
-
-This becomes your baseline.
-
----
-
-### **Step 2: Match the Environment**
-
-Now consider the walk itself:
-
-#### **High-energy dogs**
-
-Need:
-
-* Long routes
-* Open space
-* Opportunities to run
-
-Best environments:
-
-* Wide trails
-* Open countryside
-* Low restriction areas
-
----
-
-**Sensitive or reactive dogs**
-
-Need:
-
-* Predictability
-* Space from others
-* Low stimulation
-
-Best environments:
-
-* Quiet trails
-* Low dog traffic areas
-* Wide paths with visibility
-
----
-
-#### **Older or recovering dogs**
-
-Need:
-
-* Shorter distances
-* Even terrain
-* Shade
-
-Best environments:
-
-* Flat trails
-* Forest paths
-* Low-exertion routes
-
----
-
-### **Step 3: Look Beyond the Surface**
-
-A trail might look perfect, but details matter:
-
-* Is it narrow or open?
-* Is there shade?
-* Are dogs typically off-leash there?
-* Is it busy at certain times?
-
-These small factors make a big difference.
-
----
-
-### **Step 4: Pay Attention to Feedback**
-
-Your dog will tell you if it’s working.
-
-Look for:
-
-* Relaxed body language
-* Natural curiosity
-* Steady energy (not frantic or shut down)
-* Willing engagement with surroundings
-
-If you’re seeing stress signals, it may not be the right fit.
-
----
-
-### **Step 5: Prioritise Variety Intentionally**
-
-Variety is important.
-
-But random variety isn’t helpful.
-
-Instead:
-
-* Rotate between environments that suit your dog
-* Gradually introduce new challenges
-* Build confidence over time
-
----
-
-### **Final Thoughts**
-
-The best walk isn’t the longest or the most popular.
-
-It’s the one that fits your dog.
-
-Because when you choose the right environment, you’re not just going for a walk, you’re creating a better experience for both of you.
-
-
diff --git a/public/raw-blogs/how-to-give-a-reactive-dog-a-fulfilling-life-without-avoiding-the-world.md b/public/raw-blogs/how-to-give-a-reactive-dog-a-fulfilling-life-without-avoiding-the-world.md
deleted file mode 100644
index 66cb4d5..0000000
--- a/public/raw-blogs/how-to-give-a-reactive-dog-a-fulfilling-life-without-avoiding-the-world.md
+++ /dev/null
@@ -1,120 +0,0 @@
-### **Introduction**
-
-Living with a reactive dog can feel limiting.
-
-You might:
-
-* Avoid certain places
-* Walk at odd hours
-* Stick to the same safe routes
-
-But here’s the truth:
-
-Your dog can still have a full, enriching life.
-
-It just requires a different approach.
-
----
-
-## **What Reactivity Often Means**
-
-Reactivity isn’t “bad behaviour.”
-
-It’s usually:
-
-* Overstimulation
-* Fear or uncertainty
-* Lack of space
-* Too much, too quickly
-
----
-
-## **Environment Matters More Than Training Alone**
-
-Training is important, but environment is foundational.
-
-Even a well-trained dog can struggle in:
-
-* Busy areas
-* Narrow paths
-* High dog-traffic zones
-
----
-
-## **Choosing the Right Environments**
-
-Look for places that offer:
-
-* Space to move away
-* Predictability
-* Lower levels of stimulation
-
-Examples:
-
-* Wide trails
-* Quiet countryside
-* Off-peak walking times
-
----
-
-## **Give Them the Right Kind of Freedom**
-
-Reactive dogs don’t need:
-
-* More pressure
-* More exposure too quickly
-
-They need:
-
-* Controlled experiences
-* Space to decompress
-* Opportunities to succeed
-
----
-
-## **Common Mistakes**
-
-* Taking them to busy “dog-friendly” areas
-* Forcing social interactions
-* Ignoring early stress signals
-
----
-
-## **Building Confidence Over Time**
-
-Start small.
-
-* Familiar environments
-* Gradual changes
-* Positive reinforcement
-
-Confidence grows through:
-
-Consistent, successful experiences
-
----
-
-## **Fulfilment Looks Different**
-
-A fulfilling life doesn’t mean:
-
-* Busy parks
-* Social environments
-
-It means:
-
-* Calm exploration
-* Comfortable movement
-* Feeling safe in the world
-
----
-
-## **Final Thoughts**
-
-Your dog doesn’t need to handle everything.
-
-They just need the **right environments to thrive in**.
-
-And when you give them that, everything starts to shift.
-
-
diff --git a/public/raw-blogs/off-leash-dog-rules-in-portugal-what-you-need-to-know-in-2026.md b/public/raw-blogs/off-leash-dog-rules-in-portugal-what-you-need-to-know-in-2026.md
deleted file mode 100644
index ee724fe..0000000
--- a/public/raw-blogs/off-leash-dog-rules-in-portugal-what-you-need-to-know-in-2026.md
+++ /dev/null
@@ -1,125 +0,0 @@
-### **Introduction**
-
-Letting your dog off-leash is one of the simplest ways to give them freedom, enrichment, and a more natural experience.
-
-But if you’re living in or visiting Portugal, the rules aren’t always obvious, and getting it wrong can lead to fines, unsafe situations, or conflict with others.
-
-Here’s what you need to know.
-
----
-
-### **Are Dogs Allowed Off-Leash in Portugal?**
-
-In general, dogs in Portugal are expected to be **under control at all times in public spaces**.
-
-That doesn’t always mean physically on a leash - but it *does* mean:
-
-* Your dog must respond reliably to commands
-* They must not pose a risk to people, other animals, or property
-* They must not cause disturbance
-
-In many **urban areas**, leash use is effectively required.
-In more **rural or remote areas**, off-leash walking is more commonly accepted - but still comes with responsibility.
-
----
-
-### **Official Rules, Restrictions, and Fines**
-
-In Portugal, there are also specific legal restrictions to be aware of, especially around beaches and public spaces. During the summer season (typically June to September), many beaches prohibit dogs entirely, regardless of whether they are on or off-leash. These rules are set by local municipalities and are usually clearly signposted at beach entrances. Outside of summer, some beaches become dog-friendly again, but leash expectations can still apply.
-
-Failing to follow these rules can result in on-the-spot fines, which typically range from around €25 up to €250 or more, depending on the situation and location. Additional penalties may apply if a dog is considered out of control, causes disturbance, or poses a risk to others.
-
-Because enforcement and rules can vary by region, it’s always worth checking local signage before letting your dog off-leash, especially in popular or seasonal areas.
-
----
-
-### **Where Off-Leash Walking Is (Usually) Acceptable**
-
-You’re more likely to safely and responsibly walk your dog off-leash in:
-
-* Quiet countryside trails
-* Forest paths with low foot traffic
-* Remote coastal routes (away from crowds)
-* Open land where visibility is high
-
-However, even in these areas, it’s not just about permission - it’s about suitability for your dog.
-
----
-
-### **Where You Should Keep Your Dog On-Leash**
-
-There are several environments where off-leash walking is **not recommended or restricted**:
-
-* Busy beaches (especially during peak season)
-* Urban parks and promenades
-* Narrow cliff paths
-* Areas with livestock or wildlife
-* High dog-traffic zones
-
-Even if technically allowed, these environments can be:
-
-* Overstimulating
-* Unsafe
-* Stressful for reactive or sensitive dogs
-
----
-
-### **The Risks Most Dog Owners Overlook**
-
-Many owners assume off-leash = freedom.
-
-But without the right environment, it can quickly become the opposite.
-
-Common risks include:
-
-* Uncontrolled interactions with other dogs
-* Encounters with wildlife or livestock
-* Sudden terrain hazards (cliffs, unstable ground)
-* Overheating in exposed areas
-* Poor recall in unfamiliar settings
-
-The result? Stress for both you *and* your dog.
-
----
-
-### **Why “Dog-Friendly” Isn’t Enough**
-
-A beach might allow dogs.
-A trail might be popular with dog walkers.
-
-But that doesn’t mean it’s **right for your dog**.
-
-Every dog has different needs:
-
-* Some thrive in social, high-energy spaces
-* Others need quiet, predictable environments
-* Some need open space to run
-* Others need structured, low-stimulation walks
-
-Choosing the wrong environment can undo the very thing you’re trying to give them.
-
----
-
-### **How to Choose the Right Off-Leash Environment**
-
-Before letting your dog off-leash, ask:
-
-* How busy is this area?
-* Are there other dogs nearby?
-* Is the terrain safe and visible?
-* Is there wildlife or livestock?
-* Will my dog feel confident here, or overwhelmed?
-
-The goal isn’t just freedom.
-It’s **setting your dog up for a good time**.
-
----
-
-### **Final Thoughts**
-
-Walking your dog off-leash in Portugal can be an awesome experience, when it’s done in the right place, at the right time, for the right dog.
-
-Because it’s not just about whether dogs are allowed.
-It’s about whether the environment actually fits.
-
-
\ No newline at end of file
diff --git a/public/raw-blogs/the-importance-of-variety-in-your-dogs-life-and-how-to-do-it-right.md b/public/raw-blogs/the-importance-of-variety-in-your-dogs-life-and-how-to-do-it-right.md
deleted file mode 100644
index 9004f5c..0000000
--- a/public/raw-blogs/the-importance-of-variety-in-your-dogs-life-and-how-to-do-it-right.md
+++ /dev/null
@@ -1,115 +0,0 @@
-### **Introduction**
-
-Most dogs live very predictable lives.
-
-The same route.
-The same pace.
-The same environment.
-
-And while routine has its place, too much of it can limit your dog’s experience of the world.
-
----
-
-## **Why Variety Matters**
-
-Dogs are naturally curious.
-
-They’re wired to:
-
-* Explore
-* Smell
-* Navigate new environments
-
-When every walk is the same, they miss out on:
-
-* Mental stimulation
-* Physical engagement
-* Confidence-building experiences
-
----
-
-## **It’s Not Just About Exercise**
-
-A longer walk doesn’t always mean a better walk.
-
-A short walk in a new environment can be:
-
-* More stimulating
-* More engaging
-* More fulfilling
-
----
-
-## **The Benefits of Variety**
-
-Introducing new environments can:
-
-* Reduce boredom
-* Improve behaviour
-* Build confidence
-* Strengthen your bond
-
----
-
-## **But Random Variety Isn’t the Answer**
-
-This is where many owners get it wrong.
-
-Throwing your dog into:
-
-* Busy environments
-* Unpredictable situations
-* Overstimulating spaces
-
-Can actually:
-
-* Increase stress
-* Lead to reactivity
-* Create negative experiences
-
----
-
-## **How to Introduce Variety Properly**
-
-### **1. Start with similar environments**
-
-If your dog is used to quiet trails, try new *quiet* trails first.
-
----
-
-### **2. Change one variable at a time**
-
-* New location, same energy level
-* New terrain, same level of stimulation
-
----
-
-### **3. Watch your dog’s response**
-
-Let their behaviour guide your decisions.
-
----
-
-### **4. Build gradually**
-
-Confidence grows with positive experiences.
-
----
-
-## **The Goal**
-
-Not constant novelty.
-
-But **intentional variation** that suits your dog.
-
----
-
-## **Final Thoughts**
-
-Your dog doesn’t need more walks.
-
-They need **better, more varied experiences**.
-
-Because when you get it right, even a simple walk can feel completely different.
-
-
diff --git a/public/raw-blogs/top-10-hikes-to-do-with-your-dog-in-lagos-and-the-algarve.md b/public/raw-blogs/top-10-hikes-to-do-with-your-dog-in-lagos-and-the-algarve.md
deleted file mode 100644
index 2edca03..0000000
--- a/public/raw-blogs/top-10-hikes-to-do-with-your-dog-in-lagos-and-the-algarve.md
+++ /dev/null
@@ -1,86 +0,0 @@
-### **Introduction**
-
-If you’re based in or visiting Lagos, you’re surrounded by some of the most beautiful walking routes in Europe.
-
-But not all hikes are equal - especially when you’re walking with a dog.
-
-Some are:
-
-* Too exposed
-* Too busy
-* Too steep
-* Or just not suited to your dog’s needs
-
-Here are 10 of the best dog-friendly hikes in the Algarve, plus what makes each one a good fit.
-
----
-
-## **1. Ponta da Piedade Coastal Walk**
-
-**Best for:** Calm, confident dogs
- **Type:** Cliffside / scenic
-
-Incredible views, but:
-
-* Narrow in parts
-* High foot traffic
-
-Best early morning or off-season
-
----
-
-## **2. Mata Nacional de Barão de São João**
-
-**Best for:** Most dogs
- **Type:** Forest / shaded
-
-* Wide trails
-* Plenty of shade
-* Lower stimulation
-
----
-
-## **3. Ria de Alvor Nature Reserve**
-
-**Best for:** Low to moderate energy dogs
- **Type:** Boardwalk / coastal
-
-* Flat and accessible
-* Can be busy
-* Limited shade
-
----
-
-## **How to Choose the Right One**
-
-Instead of asking:
-
-“Which hike is best?”
-
-Ask:
-
-“Which hike is right for my dog?”
-
-Consider:
-
-* Energy level
-* Sociability
-* Confidence
-* Weather
-* Time of day
-
----
-
-## **Final Thoughts**
-
-The Algarve is full of incredible places to explore with your dog.
-
-But the best walks aren’t just beautiful.
-
-They’re the ones that:
-
-* Suit your dog
-* Feel comfortable
-* And allow them to be at their best
-
-
\ No newline at end of file
diff --git a/public/raw-blogs/walking-your-dog-in-the-algarve-hidden-dangers-every-owner-should-know.md b/public/raw-blogs/walking-your-dog-in-the-algarve-hidden-dangers-every-owner-should-know.md
deleted file mode 100644
index 95ef945..0000000
--- a/public/raw-blogs/walking-your-dog-in-the-algarve-hidden-dangers-every-owner-should-know.md
+++ /dev/null
@@ -1,71 +0,0 @@
-### **Introduction**
-
-The Algarve is one of the best places in Europe to explore with your dog.
-
-Cliffside trails.
-Quiet forests.
-Open countryside.
-
-But beneath all that beauty, there are a few **less obvious risks** that many dog owners (especially newcomers) don’t see coming.
-Knowing what to look out for can make the difference between a great walk and an emergency vet visit.
-
----
-
-## **1. Pine Processionary Caterpillars (High Risk)**
-
-These are one of the **most dangerous hazards** for dogs in Portugal.
-
-They appear in:
-
-* Pine forests
-* Woodland trails
-* Warmer months (typically late winter to spring)
-
-### **Why they’re dangerous:**
-
-Their tiny hairs contain a toxin that can cause:
-
-* Severe swelling of the mouth and tongue
-* Vomiting
-* Difficulty breathing
-* Tissue damage (in serious cases)
-
-### **What to look for:**
-
-* Caterpillars moving in a line (procession)
-* Nests in pine trees (silk-like bundles)
-
----
-
-## **2. Grass Seeds (Foxtails)**
-
-Small, sharp, and incredibly problematic.
-
-They’re common in:
-
-* Dry grasslands
-* Trail edges
-* Late spring and summer
-
-### **Why they’re dangerous:**
-
-They can lodge in:
-
-* Noses
-* Ears
-* Eyes
-* Between toes
-
----
-
-## **Final Thoughts**
-
-Walking your dog in the Algarve can be one of the best parts of living or visiting here.
-
-But the best walks happen when you:
-
-* Know what to look out for
-* Choose environments intentionally
-* Match the walk to your dog’s needs
-
-
\ No newline at end of file
diff --git a/public/robots.txt b/public/robots.txt
index 6018e70..1abe648 100644
--- a/public/robots.txt
+++ b/public/robots.txt
@@ -12,3 +12,5 @@ Allow: /
User-agent: *
Allow: /
+
+Sitemap: https://tailtrails.club/sitemap.xml
\ No newline at end of file
diff --git a/public/sitemap.xml b/public/sitemap.xml
new file mode 100644
index 0000000..1ee26a2
--- /dev/null
+++ b/public/sitemap.xml
@@ -0,0 +1,123 @@
+
+
+
+ https://tailtrails.club/
+ 2026-08-24
+ weekly
+ 1.0
+
+
+ https://tailtrails.club/blog
+ 2026-08-24
+ weekly
+ 0.9
+
+
+ https://tailtrails.club/compare
+ 2026-08-24
+ weekly
+ 0.9
+
+
+ https://tailtrails.club/compare/dog-walking-apps-compared
+ 2026-08-24
+ monthly
+ 0.8
+
+
+ https://tailtrails.club/compare/tailtrails-vs-wooftrax
+ 2026-08-24
+ monthly
+ 0.7
+
+
+ https://tailtrails.club/compare/tailtrails-vs-tractive
+ 2026-08-24
+ monthly
+ 0.7
+
+
+ https://tailtrails.club/compare/tailtrails-vs-alltrails
+ 2026-08-24
+ monthly
+ 0.7
+
+
+ https://tailtrails.club/compare/tailtrails-vs-fitbark
+ 2026-08-24
+ monthly
+ 0.7
+
+
+ https://tailtrails.club/compare/tailtrails-vs-pitpat
+ 2026-08-24
+ monthly
+ 0.7
+
+
+ https://tailtrails.club/privacy
+ 2026-08-24
+ yearly
+ 0.3
+
+
+ https://tailtrails.club/terms
+ 2026-08-24
+ yearly
+ 0.3
+
+
+ https://tailtrails.club/forget-me
+ 2026-08-24
+ yearly
+ 0.3
+
+
+ https://tailtrails.club/finalize-forget-me
+ 2026-08-24
+ yearly
+ 0.3
+
+
+ https://tailtrails.club/blog/best-off-leash-areas-for-dogs-in-lagos-and-nearby
+ 2026-08-24
+ monthly
+ 0.7
+
+
+ https://tailtrails.club/blog/how-to-choose-the-right-walk-for-your-dog-based-on-their-personality-and-needs
+ 2026-08-24
+ monthly
+ 0.7
+
+
+ https://tailtrails.club/blog/how-to-give-a-reactive-dog-a-fulfilling-life-without-avoiding-the-world
+ 2026-08-24
+ monthly
+ 0.7
+
+
+ https://tailtrails.club/blog/off-leash-dog-rules-in-portugal-what-you-need-to-know-in-2026
+ 2026-08-24
+ monthly
+ 0.7
+
+
+ https://tailtrails.club/blog/the-importance-of-variety-in-your-dogs-life-and-how-to-do-it-right
+ 2026-08-24
+ monthly
+ 0.7
+
+
+ https://tailtrails.club/blog/top-10-hikes-to-do-with-your-dog-in-lagos-and-the-algarve
+ 2026-08-24
+ monthly
+ 0.7
+
+
+ https://tailtrails.club/blog/walking-your-dog-in-the-algarve-hidden-dangers-every-owner-should-know
+ 2026-08-24
+ monthly
+ 0.7
+
+
\ No newline at end of file
diff --git a/scripts/generate-blog-images.sh b/scripts/generate-blog-images.sh
new file mode 100755
index 0000000..32acd75
--- /dev/null
+++ b/scripts/generate-blog-images.sh
@@ -0,0 +1,46 @@
+#!/usr/bin/env bash
+# Generate one topical image per blog post with stable-diffusion.cpp
+# using Juggernaut XL v9 (photoreal SDXL fine-tune).
+# euler_a + 1024² + no --mmap is the stable combo on Apple Metal here
+# (DPM++2M/Karras/--mmap segfault on this M4 — known large-matrix Metal issue).
+# Outputs WebP into public/blog-images/.webp.
+set -euo pipefail
+
+SD=~/stable-diffusion.cpp/build/bin/sd-cli
+MODEL=~/sd-models/juggernautXL_v9.safetensors
+OUT=/Users/jamestwose/Coding/tt-website/public/blog-images
+TMP=/tmp/sd_blog
+# Juggernaut README: heavy negatives hurt more than they help — keep it minimal.
+NEG="text, watermark, signature, low quality, deformed, extra limbs"
+STEPS=${STEPS:-20}
+
+mkdir -p "$OUT" "$TMP"
+
+# slug|prompt (prompts use Juggernaut's reliable tokens: Wildlife/Landscape
+# Photography, Hyperdetailed Photography, Cinematic, natural light)
+POSTS=(
+"best-off-leash-areas-for-dogs-in-lagos-and-nearby|Wildlife Photography, a happy dog running off-leash on a wide open sandy path through a Portuguese pine forest, dappled golden sunlight, Hyperdetailed Photography, natural light"
+"how-to-choose-the-right-walk-for-your-dog-based-on-their-personality-and-needs|Wildlife Photography, a dog owner walking a calm happy dog on a quiet countryside dirt path at sunrise, soft warm light, Hyperdetailed Photography"
+"how-to-give-a-reactive-dog-a-fulfilling-life-without-avoiding-the-world|Wildlife Photography, a calm dog on a quiet empty woodland trail with plenty of space, soft natural morning light, peaceful, Hyperdetailed Photography"
+"off-leash-dog-rules-in-portugal-what-you-need-to-know-in-2026|Landscape Photography, a dog on a lead beside a coastal cliff path in Portugal with a blue ocean and sky, summer, Hyperdetailed Photography, Cinematic"
+"the-importance-of-variety-in-your-dogs-life-and-how-to-do-it-right|Wildlife Photography, a curious dog discovering a new forest trail, sniffing the ground, vibrant green foliage, Hyperdetailed Photography, natural light"
+"top-10-hikes-to-do-with-your-dog-in-lagos-and-the-algarve|Landscape Photography, a hiker with a dog on a coastal cliff trail in the Algarve Portugal, dramatic golden ocean views at sunset, Hyperdetailed Photography, Cinematic"
+"walking-your-dog-in-the-algarve-hidden-dangers-every-owner-should-know|Wildlife Photography, a dog walking through a sunlit pine forest in Portugal, dappled light, natural mood, Hyperdetailed Photography"
+)
+
+i=0
+for entry in "${POSTS[@]}"; do
+ slug="${entry%%|*}"
+ prompt="${entry##*|}"
+ i=$((i+1))
+ png="$TMP/$slug.png"
+ webp="$OUT/$slug.webp"
+ echo "[$i/${#POSTS[@]}] $slug (steps=$STEPS)"
+ "$SD" -m "$MODEL" -p "$prompt" -n "$NEG" \
+ -H 1024 -W 1024 --steps "$STEPS" --cfg-scale 5.0 --rng std_default \
+ -s $((i*1000)) -o "$png" >/tmp/sd_blog_$slug.log 2>&1 || {
+ echo " ✗ generation failed (see /tmp/sd_blog_$slug.log)"; exit 1; }
+ cwebp -quiet -resize 1280 0 -q 82 "$png" -o "$webp" 2>/dev/null
+ echo " -> $(ls -lh "$webp" | awk '{print $5}') $webp"
+done
+echo "✅ done"
\ No newline at end of file
diff --git a/scripts/generate-sitemap.mjs b/scripts/generate-sitemap.mjs
new file mode 100644
index 0000000..69f9f71
--- /dev/null
+++ b/scripts/generate-sitemap.mjs
@@ -0,0 +1,64 @@
+/**
+ * Generate sitemap.xml for TailTrails.
+ * Run: node scripts/generate-sitemap.mjs
+ * Output: public/sitemap.xml (copied to dist/ by the subsequent vite build)
+ *
+ * Blog slugs are auto-discovered from src/blogs/posts/*.tsx so the sitemap
+ * can't drift from the actual posts.
+ */
+import fs from "fs";
+import path from "path";
+import { fileURLToPath } from "url";
+
+const __dirname = path.dirname(fileURLToPath(import.meta.url));
+const SITE_URL = "https://tailtrails.club";
+const POSTS_DIR = path.resolve(__dirname, "..", "src", "blogs", "posts");
+const TODAY = new Date().toISOString().split("T")[0];
+
+const staticRoutes = [
+ { path: "/", priority: "1.0", changefreq: "weekly" },
+ { path: "/blog", priority: "0.9", changefreq: "weekly" },
+ { path: "/compare", priority: "0.9", changefreq: "weekly" },
+ { path: "/compare/dog-walking-apps-compared", priority: "0.8", changefreq: "monthly" },
+ { path: "/compare/tailtrails-vs-wooftrax", priority: "0.7", changefreq: "monthly" },
+ { path: "/compare/tailtrails-vs-tractive", priority: "0.7", changefreq: "monthly" },
+ { path: "/compare/tailtrails-vs-alltrails", priority: "0.7", changefreq: "monthly" },
+ { path: "/compare/tailtrails-vs-fitbark", priority: "0.7", changefreq: "monthly" },
+ { path: "/compare/tailtrails-vs-pitpat", priority: "0.7", changefreq: "monthly" },
+ { path: "/privacy", priority: "0.3", changefreq: "yearly" },
+ { path: "/terms", priority: "0.3", changefreq: "yearly" },
+ { path: "/forget-me", priority: "0.3", changefreq: "yearly" },
+ { path: "/finalize-forget-me", priority: "0.3", changefreq: "yearly" },
+ // /download is a redirect stub — not indexed, omitted from sitemap.
+];
+
+const blogSlugs = fs.existsSync(POSTS_DIR)
+ ? fs.readdirSync(POSTS_DIR).filter((f) => f.endsWith(".tsx")).map((f) => f.replace(/\.tsx$/, ""))
+ : [];
+const blogRoutes = blogSlugs.map((slug) => ({
+ path: `/blog/${slug}`,
+ priority: "0.7",
+ changefreq: "monthly",
+}));
+
+const allRoutes = [...staticRoutes, ...blogRoutes];
+
+const xmlUrls = allRoutes
+ .map(
+ (r) => `
+ ${SITE_URL}${r.path}
+ ${TODAY}
+ ${r.changefreq}
+ ${r.priority}
+ `
+ )
+ .join("\n");
+
+const sitemap = `
+
+${xmlUrls}
+`;
+
+const outputPath = path.join(__dirname, "..", "public", "sitemap.xml");
+fs.writeFileSync(outputPath, sitemap, "utf8");
+console.log(`✅ Sitemap generated: ${outputPath} (${allRoutes.length} URLs)`);
\ No newline at end of file
diff --git a/scripts/prerender.mjs b/scripts/prerender.mjs
new file mode 100644
index 0000000..8afadd1
--- /dev/null
+++ b/scripts/prerender.mjs
@@ -0,0 +1,211 @@
+#!/usr/bin/env node
+/**
+ * Pre-render script for TailTrails
+ *
+ * Renders every route in Puppeteer so crawlers see full HTML content
+ * (blogs, landing, legal pages), and injects a unique +
+ * per page for SEO.
+ *
+ * Usage: node scripts/prerender.mjs
+ * Runs as part of: npm run build
+ */
+import puppeteer from "puppeteer";
+import { createServer } from "http";
+import { fileURLToPath } from "url";
+import path from "path";
+import fs from "fs";
+
+const __dirname = path.dirname(fileURLToPath(import.meta.url));
+const DIST_DIR = path.resolve(__dirname, "..", "dist");
+const POSTS_DIR = path.resolve(__dirname, "..", "src", "blogs", "posts");
+const CONCURRENCY = Number(process.env.PRERENDER_CONCURRENCY) || 6;
+
+// ── Static routes ────────────────────────────────────────────────────────────
+const STATIC_ROUTES = [
+ "/", "/blog", "/compare",
+ "/compare/dog-walking-apps-compared",
+ "/compare/tailtrails-vs-wooftrax",
+ "/compare/tailtrails-vs-tractive",
+ "/compare/tailtrails-vs-alltrails",
+ "/compare/tailtrails-vs-fitbark",
+ "/compare/tailtrails-vs-pitpat",
+ "/privacy", "/terms",
+ "/forget-me", "/finalize-forget-me",
+];
+
+// ── Per-route SEO metadata ───────────────────────────────────────────────────
+const DEFAULT_TITLE = "TailTrails — Life Unleashed";
+const DEFAULT_DESC =
+ "Discover new trails that match your dog's needs, and turn everyday walks into real adventures. Download TailTrails on iOS and Android.";
+
+const STATIC_SEO = {
+ "/": { title: DEFAULT_TITLE, desc: DEFAULT_DESC },
+ "/blog": {
+ title: "TailTrails Blog — Dog Walking Tips, Trails & Guides",
+ desc: "Guides on choosing the right walks for your dog, off-leash rules in Portugal, hidden dangers, and the best hikes in the Algarve.",
+ },
+ "/privacy": { title: "Privacy Policy — TailTrails", desc: "How TailTrails handles your data and privacy." },
+ "/terms": { title: "Terms & Conditions — TailTrails", desc: "The terms and conditions for using TailTrails." },
+ "/forget-me": { title: "Delete Your Account — TailTrails", desc: "Request deletion of your TailTrails account and data." },
+ "/finalize-forget-me": { title: "Confirm Account Deletion — TailTrails", desc: "Confirm deletion of your TailTrails account." },
+ "/download": { title: "Download TailTrails — iOS & Android", desc: "Get TailTrails on the App Store or Google Play." },
+};
+
+// ── Discover blog slugs + metadata from src/blogs/posts/*.tsx ────────────────
+// ponytail: read slugs from the filesystem so the prerender list can't drift
+// from the actual posts. Meta is regex-pulled from each file's `export const meta`.
+function discoverPosts() {
+ if (!fs.existsSync(POSTS_DIR)) return [];
+ return fs.readdirSync(POSTS_DIR)
+ .filter((f) => f.endsWith(".tsx"))
+ .map((f) => {
+ const slug = f.replace(/\.tsx$/, "");
+ const src = fs.readFileSync(path.join(POSTS_DIR, f), "utf-8");
+ const title = src.match(/title:\s*'([^']*)'/)?.[1];
+ const description = src.match(/description:\s*'([^']*)'/)?.[1];
+ return { slug, title, description };
+ });
+}
+
+const posts = discoverPosts();
+const BLOG_ROUTES = posts.map((p) => `/blog/${p.slug}`);
+
+// ── Static file server (SPA fallback) ────────────────────────────────────────
+function startServer(port) {
+ const mimes = {
+ ".html": "text/html", ".js": "application/javascript", ".mjs": "application/javascript",
+ ".css": "text/css", ".json": "application/json", ".png": "image/png", ".jpg": "image/jpeg",
+ ".jpeg": "image/jpeg", ".gif": "image/gif", ".svg": "image/svg+xml", ".ico": "image/x-icon",
+ ".woff": "font/woff", ".woff2": "font/woff2", ".ttf": "font/ttf", ".webp": "image/webp",
+ ".avif": "image/avif", ".mp4": "video/mp4", ".txt": "text/plain",
+ };
+ return new Promise((resolve, reject) => {
+ const server = createServer((req, res) => {
+ let fp = path.join(DIST_DIR, req.url === "/" ? "index.html" : req.url);
+ if (!fs.existsSync(fp) || fs.statSync(fp).isDirectory()) fp = path.join(DIST_DIR, "index.html");
+ fs.readFile(fp, (err, data) => {
+ if (err) { res.writeHead(404); res.end("Not found"); return; }
+ res.writeHead(200, { "Content-Type": mimes[path.extname(fp)] || "application/octet-stream" });
+ res.end(data);
+ });
+ });
+ server.listen(port, () => resolve(server));
+ server.on("error", reject);
+ });
+}
+
+// ── Fallback-only SEO injection ─────────────────────────────────────────────
+// Every prerendered route now mounts a component that sets ,
+// description, OG, Twitter, canonical and JSON-LD during the Puppeteer render.
+// This only fills in the gaps if a page forgot to mount (title still the
+// index.html placeholder "Tail Trails", or no description meta present).
+function injectSeo(html, title, desc) {
+ let out = html;
+ if (title && /Tail Trails<\/title>/i.test(out)) {
+ out = out.replace(/Tail Trails<\/title>/i, `${title}`);
+ }
+ if (desc && !/", ``);
+ }
+ return out;
+}
+
+function seoFor(route) {
+ if (STATIC_SEO[route]) return STATIC_SEO[route];
+ const post = route.startsWith("/blog/") ? posts.find((p) => `/blog/${p.slug}` === route) : null;
+ if (post) {
+ return {
+ title: post.title ? `${post.title} — TailTrails Blog` : "TailTrails Blog",
+ desc: post.description || DEFAULT_DESC,
+ };
+ }
+ return { title: DEFAULT_TITLE, desc: DEFAULT_DESC };
+}
+
+// ── Render one page ──────────────────────────────────────────────────────────
+async function prerenderRoute(browser, url, route) {
+ const page = await browser.newPage();
+ try {
+ await page.goto(url, { waitUntil: "networkidle0", timeout: 20000 });
+ await page.waitForFunction(
+ () => { const r = document.getElementById("root"); return r && r.children.length > 0; },
+ { timeout: 10000 }
+ );
+ // let animations / images settle
+ await new Promise((r) => setTimeout(r, 400));
+ let html = await page.content();
+ const { title, desc } = seoFor(route);
+ html = injectSeo(html, title, desc);
+ const outDir = route === "/" ? DIST_DIR : path.join(DIST_DIR, route);
+ fs.mkdirSync(outDir, { recursive: true });
+ fs.writeFileSync(path.join(outDir, "index.html"), html, "utf-8");
+ return { route, ok: true };
+ } catch (err) {
+ return { route, ok: false, error: err.message };
+ } finally {
+ await page.close();
+ }
+}
+
+// ── Parallel batch renderer ──────────────────────────────────────────────────
+async function renderBatch(browser, routes, baseUrl, concurrency) {
+ let done = 0;
+ const total = routes.length;
+ const errors = [];
+ for (let i = 0; i < total; i += concurrency) {
+ const batch = routes.slice(i, i + concurrency);
+ const results = await Promise.all(batch.map((r) => prerenderRoute(browser, `${baseUrl}${r}`, r)));
+ for (const r of results) {
+ done++;
+ r.ok
+ ? console.log(` ✓ [${done}/${total}] ${r.route}`)
+ : console.error(` ✗ [${done}/${total}] ${r.route}: ${r.error}`);
+ if (!r.ok) errors.push(r.route);
+ }
+ }
+ return errors;
+}
+
+// ── Main ─────────────────────────────────────────────────────────────────────
+async function main() {
+ if (!fs.existsSync(DIST_DIR)) {
+ console.error("Error: dist/ not found. Run 'vite build' first.");
+ process.exit(1);
+ }
+
+ console.log("🔄 Pre-rendering pages for SEO...\n");
+ console.log(` Discovered ${posts.length} blog post(s): ${posts.map((p) => p.slug).join(", ")}\n`);
+
+ const routes = [...STATIC_ROUTES, ...BLOG_ROUTES];
+ const PORT = 4823;
+ const BASE = `http://localhost:${PORT}`;
+ const server = await startServer(PORT);
+ console.log(` Serving dist/ on ${BASE}`);
+ console.log(` Rendering ${routes.length} pages in Puppeteer (concurrency ${CONCURRENCY})...\n`);
+
+ const browser = await puppeteer.launch({
+ headless: true,
+ args: ["--no-sandbox", "--disable-setuid-sandbox", "--disable-gpu"],
+ });
+ const errors = await renderBatch(browser, routes, BASE, CONCURRENCY);
+ await browser.close();
+ server.close();
+
+ console.log(`\n✅ Pre-rendered ${routes.length} pages.`);
+ if (errors.length) console.log(` ⚠️ ${errors.length} route(s) failed: ${errors.join(", ")}`);
+
+ // Verify key pages
+ console.log("\n📋 Verifying key pages...\n");
+ const verify = ["/", "/blog", ...(BLOG_ROUTES.length ? [BLOG_ROUTES[0]] : [])];
+ for (const route of verify) {
+ const fp = route === "/" ? path.join(DIST_DIR, "index.html") : path.join(DIST_DIR, route, "index.html");
+ if (!fs.existsSync(fp)) { console.log(` ⚠ ${route}: not found`); continue; }
+ const html = fs.readFileSync(fp, "utf-8");
+ const title = html.match(/(.*?)<\/title>/)?.[1] || "MISSING";
+ const desc = html.match(/ { console.error("Pre-rendering failed:", err); process.exit(1); });
\ No newline at end of file
diff --git a/src/App.tsx b/src/App.tsx
index f2d767a..f264621 100644
--- a/src/App.tsx
+++ b/src/App.tsx
@@ -1,32 +1,61 @@
-import { BrowserRouter, Routes, Route } from "react-router-dom";
+import { BrowserRouter, Routes, Route, useLocation } from "react-router-dom";
+import { useEffect } from "react";
import Index from "./pages/Index";
import Privacy from "./pages/Privacy";
import Terms from "./pages/Terms";
import NotFound from "./pages/NotFound";
-import Waitlist from "./pages/Waitlist";
import RequestAccountDeletion from "./pages/RequestAccountDeletion";
import FinalizeAccountDeletion from "./pages/FinalizeAccountDeletion";
import Download from "./pages/Download";
import BlogList from "./pages/BlogList";
import BlogPost from "./pages/BlogPost";
+import Compare from "./pages/Compare";
+import BigComparison from "./pages/compare/dog-walking-apps-compared";
+import TailtrailsVsWooftrax from "./pages/compare/tailtrails-vs-wooftrax";
+import TailtrailsVsTractive from "./pages/compare/tailtrails-vs-tractive";
+import TailtrailsVsAlltrails from "./pages/compare/tailtrails-vs-alltrails";
+import TailtrailsVsFitbark from "./pages/compare/tailtrails-vs-fitbark";
+import TailtrailsVsPitpat from "./pages/compare/tailtrails-vs-pitpat";
import CookieConsent from "./components/ui/CookieConsent";
import { ToastProvider, ToastViewport } from "./components/ui/toast";
import Toaster from "./components/ui/Toaster";
+// Client-side route changes don't trigger the browser's native anchor scroll.
+const ScrollToHash = () => {
+ const { pathname, hash } = useLocation();
+ useEffect(() => {
+ if (!hash) { window.scrollTo(0, 0); return; }
+ // wait for the destination page to render before scrolling
+ requestAnimationFrame(() => {
+ const el = document.getElementById(hash.slice(1));
+ if (el) { el.scrollIntoView({ behavior: "smooth" }); }
+ else { window.scrollTo(0, 0); }
+ });
+ }, [pathname, hash]);
+ return null;
+};
+
const App = () => (
<>
+ } />
} />
} />
- } />
} />
} />
} />
} />
} />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
+ } />
{/* ADD ALL CUSTOM ROUTES ABOVE THE CATCH-ALL "*" ROUTE */}
} />
diff --git a/src/blogs/index.ts b/src/blogs/index.ts
new file mode 100644
index 0000000..7fd31ce
--- /dev/null
+++ b/src/blogs/index.ts
@@ -0,0 +1,42 @@
+import type { ComponentType } from 'react';
+import bestOffLeash, { meta as bestOffLeashMeta } from './posts/best-off-leash-areas-for-dogs-in-lagos-and-nearby';
+import howToChoose, { meta as howToChooseMeta } from './posts/how-to-choose-the-right-walk-for-your-dog-based-on-their-personality-and-needs';
+import reactiveDog, { meta as reactiveDogMeta } from './posts/how-to-give-a-reactive-dog-a-fulfilling-life-without-avoiding-the-world';
+import offLeashRules, { meta as offLeashRulesMeta } from './posts/off-leash-dog-rules-in-portugal-what-you-need-to-know-in-2026';
+import variety, { meta as varietyMeta } from './posts/the-importance-of-variety-in-your-dogs-life-and-how-to-do-it-right';
+import topHikes, { meta as topHikesMeta } from './posts/top-10-hikes-to-do-with-your-dog-in-lagos-and-the-algarve';
+import algarveDangers, { meta as algarveDangersMeta } from './posts/walking-your-dog-in-the-algarve-hidden-dangers-every-owner-should-know';
+
+export type BlogMeta = {
+ title: string;
+ date: string;
+ description: string;
+ category: string;
+ readTime: string;
+ live: boolean;
+ image: string;
+};
+
+export type BlogEntry = {
+ slug: string;
+ meta: BlogMeta;
+ Component: ComponentType;
+};
+
+// ponytail: eager imports — 7 short text posts. Drops the `marked` runtime dep
+// and the fetch+parse of .md files; net bundle is smaller. Code-split per post
+// only if the post count grows large.
+export const posts: BlogEntry[] = [
+ { slug: 'best-off-leash-areas-for-dogs-in-lagos-and-nearby', meta: bestOffLeashMeta, Component: bestOffLeash },
+ {slug: 'how-to-choose-the-right-walk-for-your-dog-based-on-their-personality-and-needs', meta: howToChooseMeta, Component: howToChoose},
+ {slug: 'how-to-give-a-reactive-dog-a-fulfilling-life-without-avoiding-the-world', meta: reactiveDogMeta, Component: reactiveDog},
+ {slug: 'off-leash-dog-rules-in-portugal-what-you-need-to-know-in-2026', meta: offLeashRulesMeta, Component: offLeashRules},
+ {slug: 'the-importance-of-variety-in-your-dogs-life-and-how-to-do-it-right', meta: varietyMeta, Component: variety},
+ {slug: 'top-10-hikes-to-do-with-your-dog-in-lagos-and-the-algarve', meta: topHikesMeta, Component: topHikes},
+ {slug: 'walking-your-dog-in-the-algarve-hidden-dangers-every-owner-should-know', meta: algarveDangersMeta, Component: algarveDangers},
+].sort((a, b) => b.meta.date.localeCompare(a.meta.date));
+
+export const getAllPosts = (): BlogEntry[] => posts;
+
+export const getPostBySlug = (slug: string): BlogEntry | undefined =>
+ posts.find((p) => p.slug === slug);
\ No newline at end of file
diff --git a/src/blogs/posts/best-off-leash-areas-for-dogs-in-lagos-and-nearby.tsx b/src/blogs/posts/best-off-leash-areas-for-dogs-in-lagos-and-nearby.tsx
new file mode 100644
index 0000000..7bb8b16
--- /dev/null
+++ b/src/blogs/posts/best-off-leash-areas-for-dogs-in-lagos-and-nearby.tsx
@@ -0,0 +1,130 @@
+import type { BlogMeta } from '../index';
+
+export const meta: BlogMeta = {
+ title: 'Best Off-Leash Areas for Dogs in Lagos (and Nearby)',
+ date: '2024-05-01',
+ description: 'Looking for off-leash areas for dogs in Lagos, Portugal? Discover the best spots for safe, enjoyable off-leash walks, plus what to watch out for.',
+ category: 'Insights',
+ readTime: '6 min',
+ live: true,
+ image: '/blog-images/best-off-leash-areas-for-dogs-in-lagos-and-nearby.webp',
+};
+
+export default function Post() {
+ return (
+ <>
+
Introduction
+
Finding a good place to let your dog off-leash in Lagos isn't always straightforward.
+
Some areas are:
+
+
Too busy
+
Too unpredictable
+
Or not actually suitable for your dog
+
+
But when you find the right spot, it changes everything.
+
Here are some of the best off-leash-friendly areas around Lagos, and how to choose the right one for your dog.
+
+
+
+
1. Mata Nacional de Barão de São João
+
Best for: Most dogs
+
Why it works:
+
+
Wide, open forest trails
+
Plenty of space to create distance
+
Shaded and cooler
+
+
Ideal for dogs who need space without isolation
+
+
+
+
2. Praia da Bordeira (West Coast)
+
Best for: High-energy dogs
+
Why it works:
+
+
Huge open beach
+
Low crowd density (outside peak times)
+
Great for running
+
+
Watch:
+
+
Wind exposure
+
Seasonal rules
+
+
+
+
+
3. Ria de Alvor (Quiet Sections)
+
Best for: Lower-energy or calm dogs
+
Why it works:
+
+
Flat terrain
+
Open visibility
+
+
Avoid peak hours, it can get busy
+
+
+
+
4. Monchique Countryside
+
Best for: Dogs needing low stimulation
+
Why it works:
+
+
Quiet
+
Natural
+
Cooler temperatures
+
+
Great for reactive or sensitive dogs
+
+
+
+
5. Local Countryside Trails (Hidden Gems)
+
Often overlooked, but some of the best options.
+
These areas offer:
+
+
Lower dog traffic
+
More control
+
Flexible space
+
+
Especially useful for:
+
+
Training recall
+
Building confidence
+
+
Check out trails near countryside villages like Bensafrim and Vila do Bispo.
+
+
+
+
Important: Not Every "Off-Leash Area" Is Right
+
Just because a place allows off-leash doesn't mean it's suitable.
+
Before letting your dog off:
+
+
Check the environment
+
Look at dog traffic
+
Consider your dog's behaviour
+
+
+
+
+
What Makes a Good Off-Leash Spot?
+
The best places have:
+
+
Space to move freely
+
Clear visibility
+
Low unpredictability
+
An environment suited to your dog
+
+
+
+
+
Final Thoughts
+
The goal isn't just to let your dog off-leash.
+
It's to do it in a way that:
+
+
Feels safe
+
Feels calm
+
And actually benefits your dog
+
+
Because the right environment makes all the difference.
+ >
+ );
+}
\ No newline at end of file
diff --git a/src/blogs/posts/how-to-choose-the-right-walk-for-your-dog-based-on-their-personality-and-needs.tsx b/src/blogs/posts/how-to-choose-the-right-walk-for-your-dog-based-on-their-personality-and-needs.tsx
new file mode 100644
index 0000000..ef06f8b
--- /dev/null
+++ b/src/blogs/posts/how-to-choose-the-right-walk-for-your-dog-based-on-their-personality-and-needs.tsx
@@ -0,0 +1,127 @@
+import type { BlogMeta } from '../index';
+
+export const meta: BlogMeta = {
+ title: 'How to Choose the Right Walk for Your Dog (Based on Their Personality and Needs)',
+ date: '2024-04-20',
+ description: 'Not all walks are equal. Learn how to choose the right environment for your dog based on energy, temperament, and needs.',
+ category: 'Strategy',
+ readTime: '5 min',
+ live: true,
+ image: '/blog-images/how-to-choose-the-right-walk-for-your-dog-based-on-their-personality-and-needs.webp',
+};
+
+export default function Post() {
+ return (
+ <>
+
Introduction
+
Choosing a walk for your dog often comes down to convenience.
+
What's nearby. What you've done before. What seems "good enough."
+
But the best walks aren't chosen that way.
+
They're chosen based on your dog.
+
+
+
+
Step 1: Understand Your Dog's Profile
+
Start with the basics:
+
+
Energy level (low, medium, high)
+
Sociability (loves dogs vs prefers space)
+
Confidence (bold vs cautious)
+
Sensitivities (noise, movement, crowds)
+
Physical needs (age, injuries, endurance)
+
+
This becomes your baseline.
+
+
+
+
Step 2: Match the Environment
+
Now consider the walk itself:
+
+
High-energy dogs
+
Need:
+
+
Long routes
+
Open space
+
Opportunities to run
+
+
Best environments:
+
+
Wide trails
+
Open countryside
+
Low restriction areas
+
+
+
Sensitive or reactive dogs
+
Need:
+
+
Predictability
+
Space from others
+
Low stimulation
+
+
Best environments:
+
+
Quiet trails
+
Low dog traffic areas
+
Wide paths with visibility
+
+
+
Older or recovering dogs
+
Need:
+
+
Shorter distances
+
Even terrain
+
Shade
+
+
Best environments:
+
+
Flat trails
+
Forest paths
+
Low-exertion routes
+
+
+
+
+
Step 3: Look Beyond the Surface
+
A trail might look perfect, but details matter:
+
+
Is it narrow or open?
+
Is there shade?
+
Are dogs typically off-leash there?
+
Is it busy at certain times?
+
+
These small factors make a big difference.
+
+
+
+
Step 4: Pay Attention to Feedback
+
Your dog will tell you if it's working.
+
Look for:
+
+
Relaxed body language
+
Natural curiosity
+
Steady energy (not frantic or shut down)
+
Willing engagement with surroundings
+
+
If you're seeing stress signals, it may not be the right fit.
+
+
+
+
Step 5: Prioritise Variety Intentionally
+
Variety is important.
+
But random variety isn't helpful.
+
Instead:
+
+
Rotate between environments that suit your dog
+
Gradually introduce new challenges
+
Build confidence over time
+
+
+
+
+
Final Thoughts
+
The best walk isn't the longest or the most popular.
+
It's the one that fits your dog.
+
Because when you choose the right environment, you're not just going for a walk, you're creating a better experience for both of you.
+ >
+ );
+}
\ No newline at end of file
diff --git a/src/blogs/posts/how-to-give-a-reactive-dog-a-fulfilling-life-without-avoiding-the-world.tsx b/src/blogs/posts/how-to-give-a-reactive-dog-a-fulfilling-life-without-avoiding-the-world.tsx
new file mode 100644
index 0000000..48f9e72
--- /dev/null
+++ b/src/blogs/posts/how-to-give-a-reactive-dog-a-fulfilling-life-without-avoiding-the-world.tsx
@@ -0,0 +1,126 @@
+import type { BlogMeta } from '../index';
+
+export const meta: BlogMeta = {
+ title: 'How to Give a Reactive Dog a Fulfilling Life (Without Avoiding the World)',
+ date: '2024-03-15',
+ description: 'Have a reactive dog? Learn how to give them a fulfilling life with the right environments, structure, and approach.',
+ category: 'Insights',
+ readTime: '7 min',
+ live: true,
+ image: '/blog-images/how-to-give-a-reactive-dog-a-fulfilling-life-without-avoiding-the-world.webp',
+};
+
+export default function Post() {
+ return (
+ <>
+
Introduction
+
Living with a reactive dog can feel limiting.
+
You might:
+
+
Avoid certain places
+
Walk at odd hours
+
Stick to the same safe routes
+
+
But here's the truth:
+
Your dog can still have a full, enriching life.
+
It just requires a different approach.
+
+
+
+
What Reactivity Often Means
+
Reactivity isn't "bad behaviour."
+
It's usually:
+
+
Overstimulation
+
Fear or uncertainty
+
Lack of space
+
Too much, too quickly
+
+
+
+
+
Environment Matters More Than Training Alone
+
Training is important, but environment is foundational.
+
Even a well-trained dog can struggle in:
+
+
Busy areas
+
Narrow paths
+
High dog-traffic zones
+
+
+
+
+
Choosing the Right Environments
+
Look for places that offer:
+
+
Space to move away
+
Predictability
+
Lower levels of stimulation
+
+
Examples:
+
+
Wide trails
+
Quiet countryside
+
Off-peak walking times
+
+
+
+
+
Give Them the Right Kind of Freedom
+
Reactive dogs don't need:
+
+
More pressure
+
More exposure too quickly
+
+
They need:
+
+
Controlled experiences
+
Space to decompress
+
Opportunities to succeed
+
+
+
+
+
Common Mistakes
+
+
Taking them to busy "dog-friendly" areas
+
Forcing social interactions
+
Ignoring early stress signals
+
+
+
+
+
Building Confidence Over Time
+
Start small.
+
+
Familiar environments
+
Gradual changes
+
Positive reinforcement
+
+
Confidence grows through:
+
Consistent, successful experiences
+
+
+
+
Fulfilment Looks Different
+
A fulfilling life doesn't mean:
+
+
Busy parks
+
Social environments
+
+
It means:
+
+
Calm exploration
+
Comfortable movement
+
Feeling safe in the world
+
+
+
+
+
Final Thoughts
+
Your dog doesn't need to handle everything.
+
They just need the right environments to thrive in.
+
And when you give them that, everything starts to shift.
+ >
+ );
+}
\ No newline at end of file
diff --git a/src/blogs/posts/off-leash-dog-rules-in-portugal-what-you-need-to-know-in-2026.tsx b/src/blogs/posts/off-leash-dog-rules-in-portugal-what-you-need-to-know-in-2026.tsx
new file mode 100644
index 0000000..28cf269
--- /dev/null
+++ b/src/blogs/posts/off-leash-dog-rules-in-portugal-what-you-need-to-know-in-2026.tsx
@@ -0,0 +1,120 @@
+import type { BlogMeta } from '../index';
+
+export const meta: BlogMeta = {
+ title: 'Off-Leash Dog Rules in Portugal: What You Need to Know in 2026',
+ date: '2026-04-01',
+ description: 'Can you walk your dog off-leash in Portugal? Learn the rules, risks, and best practices for safe and legal off-leash walks.',
+ category: 'Trends',
+ readTime: '6 min',
+ live: true,
+ image: '/blog-images/off-leash-dog-rules-in-portugal-what-you-need-to-know-in-2026.webp',
+};
+
+export default function Post() {
+ return (
+ <>
+
Introduction
+
Letting your dog off-leash is one of the simplest ways to give them freedom, enrichment, and a more natural experience.
+
But if you're living in or visiting Portugal, the rules aren't always obvious, and getting it wrong can lead to fines, unsafe situations, or conflict with others.
+
Here's what you need to know.
+
+
+
+
Are Dogs Allowed Off-Leash in Portugal?
+
In general, dogs in Portugal are expected to be under control at all times in public spaces.
+
That doesn't always mean physically on a leash - but it does mean:
+
+
Your dog must respond reliably to commands
+
They must not pose a risk to people, other animals, or property
+
They must not cause disturbance
+
+
In many urban areas, leash use is effectively required.
+
In more rural or remote areas, off-leash walking is more commonly accepted - but still comes with responsibility.
+
+
+
+
Official Rules, Restrictions, and Fines
+
In Portugal, there are also specific legal restrictions to be aware of, especially around beaches and public spaces. During the summer season (typically June to September), many beaches prohibit dogs entirely, regardless of whether they are on or off-leash. These rules are set by local municipalities and are usually clearly signposted at beach entrances. Outside of summer, some beaches become dog-friendly again, but leash expectations can still apply.
+
Failing to follow these rules can result in on-the-spot fines, which typically range from around €25 up to €250 or more, depending on the situation and location. Additional penalties may apply if a dog is considered out of control, causes disturbance, or poses a risk to others.
+
Because enforcement and rules can vary by region, it's always worth checking local signage before letting your dog off-leash, especially in popular or seasonal areas.
+
+
+
+
Where Off-Leash Walking Is (Usually) Acceptable
+
You're more likely to safely and responsibly walk your dog off-leash in:
+
+
Quiet countryside trails
+
Forest paths with low foot traffic
+
Remote coastal routes (away from crowds)
+
Open land where visibility is high
+
+
However, even in these areas, it's not just about permission - it's about suitability for your dog.
+
+
+
+
Where You Should Keep Your Dog On-Leash
+
There are several environments where off-leash walking is not recommended or restricted:
+
+
Busy beaches (especially during peak season)
+
Urban parks and promenades
+
Narrow cliff paths
+
Areas with livestock or wildlife
+
High dog-traffic zones
+
+
Even if technically allowed, these environments can be:
+
+
Overstimulating
+
Unsafe
+
Stressful for reactive or sensitive dogs
+
+
+
+
+
The Risks Most Dog Owners Overlook
+
Many owners assume off-leash = freedom.
+
But without the right environment, it can quickly become the opposite.
+
Common risks include:
+
+
Uncontrolled interactions with other dogs
+
Encounters with wildlife or livestock
+
Sudden terrain hazards (cliffs, unstable ground)
+
Overheating in exposed areas
+
Poor recall in unfamiliar settings
+
+
The result? Stress for both you and your dog.
+
+
+
+
Why "Dog-Friendly" Isn't Enough
+
A beach might allow dogs. A trail might be popular with dog walkers.
+
But that doesn't mean it's right for your dog.
+
Every dog has different needs:
+
+
Some thrive in social, high-energy spaces
+
Others need quiet, predictable environments
+
Some need open space to run
+
Others need structured, low-stimulation walks
+
+
Choosing the wrong environment can undo the very thing you're trying to give them.
+
+
+
+
How to Choose the Right Off-Leash Environment
+
Before letting your dog off-leash, ask:
+
+
How busy is this area?
+
Are there other dogs nearby?
+
Is the terrain safe and visible?
+
Is there wildlife or livestock?
+
Will my dog feel confident here, or overwhelmed?
+
+
The goal isn't just freedom. It's setting your dog up for a good time.
+
+
+
+
Final Thoughts
+
Walking your dog off-leash in Portugal can be an awesome experience, when it's done in the right place, at the right time, for the right dog.
+
Because it's not just about whether dogs are allowed. It's about whether the environment actually fits.
+ >
+ );
+}
\ No newline at end of file
diff --git a/src/blogs/posts/the-importance-of-variety-in-your-dogs-life-and-how-to-do-it-right.tsx b/src/blogs/posts/the-importance-of-variety-in-your-dogs-life-and-how-to-do-it-right.tsx
new file mode 100644
index 0000000..ff90af3
--- /dev/null
+++ b/src/blogs/posts/the-importance-of-variety-in-your-dogs-life-and-how-to-do-it-right.tsx
@@ -0,0 +1,116 @@
+import type { BlogMeta } from '../index';
+
+export const meta: BlogMeta = {
+ title: 'The Importance of Variety in Your Dog’s Life (And How to Do It Right)',
+ date: '2024-02-28',
+ description: 'Dogs need more than the same daily walk. Learn why variety matters and how to safely introduce new environments into your dog’s routine.',
+ category: 'Strategy',
+ readTime: '5 min',
+ live: true,
+ image: '/blog-images/the-importance-of-variety-in-your-dogs-life-and-how-to-do-it-right.webp',
+};
+
+export default function Post() {
+ return (
+ <>
+
Introduction
+
Most dogs live very predictable lives.
+
The same route. The same pace. The same environment.
+
And while routine has its place, too much of it can limit your dog's experience of the world.
+
+
+
+
Why Variety Matters
+
Dogs are naturally curious.
+
They're wired to:
+
+
Explore
+
Smell
+
Navigate new environments
+
+
When every walk is the same, they miss out on:
+
+
Mental stimulation
+
Physical engagement
+
Confidence-building experiences
+
+
+
+
+
It's Not Just About Exercise
+
A longer walk doesn't always mean a better walk.
+
A short walk in a new environment can be:
+
+
More stimulating
+
More engaging
+
More fulfilling
+
+
+
+
+
The Benefits of Variety
+
Introducing new environments can:
+
+
Reduce boredom
+
Improve behaviour
+
Build confidence
+
Strengthen your bond
+
+
+
+
+
But Random Variety Isn't the Answer
+
This is where many owners get it wrong.
+
Throwing your dog into:
+
+
Busy environments
+
Unpredictable situations
+
Overstimulating spaces
+
+
Can actually:
+
+
Increase stress
+
Lead to reactivity
+
Create negative experiences
+
+
+
+
+
How to Introduce Variety Properly
+
+
1. Start with similar environments
+
If your dog is used to quiet trails, try new quiet trails first.
+
+
+
+
2. Change one variable at a time
+
+
New location, same energy level
+
New terrain, same level of stimulation
+
+
+
+
+
3. Watch your dog's response
+
Let their behaviour guide your decisions.
+
+
+
+
4. Build gradually
+
Confidence grows with positive experiences.
+
+
+
+
The Goal
+
Not constant novelty.
+
But intentional variation that suits your dog.
+
+
+
+
Final Thoughts
+
Your dog doesn't need more walks.
+
They need better, more varied experiences.
+
Because when you get it right, even a simple walk can feel completely different.
+ >
+ );
+}
\ No newline at end of file
diff --git a/src/blogs/posts/top-10-hikes-to-do-with-your-dog-in-lagos-and-the-algarve.tsx b/src/blogs/posts/top-10-hikes-to-do-with-your-dog-in-lagos-and-the-algarve.tsx
new file mode 100644
index 0000000..57830e8
--- /dev/null
+++ b/src/blogs/posts/top-10-hikes-to-do-with-your-dog-in-lagos-and-the-algarve.tsx
@@ -0,0 +1,91 @@
+import type { BlogMeta } from '../index';
+
+export const meta: BlogMeta = {
+ title: 'Top 10 Hikes to do with your Dog in Lagos and the Algarve',
+ date: '2024-06-10',
+ description: 'Discover the best hikes in Lagos and the Algarve to take your dog on. From coastal trails to quiet forests, find the right walk for your dog.',
+ category: 'Insights',
+ readTime: '8 min',
+ live: true,
+ image: '/blog-images/top-10-hikes-to-do-with-your-dog-in-lagos-and-the-algarve.webp',
+};
+
+export default function Post() {
+ return (
+ <>
+
Introduction
+
If you're based in or visiting Lagos, you're surrounded by some of the most beautiful walking routes in Europe.
+
But not all hikes are equal - especially when you're walking with a dog.
+
Some are:
+
+
Too exposed
+
Too busy
+
Too steep
+
Or just not suited to your dog's needs
+
+
Here are 10 of the best dog-friendly hikes in the Algarve, plus what makes each one a good fit.
+
+
+
+
1. Ponta da Piedade Coastal Walk
+
Best for: Calm, confident dogs
+
Type: Cliffside / scenic
+
Incredible views, but:
+
+
Narrow in parts
+
High foot traffic
+
+
Best early morning or off-season
+
+
+
+
2. Mata Nacional de Barão de São João
+
Best for: Most dogs
+
Type: Forest / shaded
+
+
Wide trails
+
Plenty of shade
+
Lower stimulation
+
+
+
+
+
3. Ria de Alvor Nature Reserve
+
Best for: Low to moderate energy dogs
+
Type: Boardwalk / coastal
+
+
Flat and accessible
+
Can be busy
+
Limited shade
+
+
+
+
+
How to Choose the Right One
+
Instead of asking:
+
"Which hike is best?"
+
Ask:
+
"Which hike is right for my dog?"
+
Consider:
+
+
Energy level
+
Sociability
+
Confidence
+
Weather
+
Time of day
+
+
+
+
+
Final Thoughts
+
The Algarve is full of incredible places to explore with your dog.
+
But the best walks aren't just beautiful.
+
They're the ones that:
+
+
Suit your dog
+
Feel comfortable
+
And allow them to be at their best
+
+ >
+ );
+}
\ No newline at end of file
diff --git a/src/blogs/posts/walking-your-dog-in-the-algarve-hidden-dangers-every-owner-should-know.tsx b/src/blogs/posts/walking-your-dog-in-the-algarve-hidden-dangers-every-owner-should-know.tsx
new file mode 100644
index 0000000..10fba42
--- /dev/null
+++ b/src/blogs/posts/walking-your-dog-in-the-algarve-hidden-dangers-every-owner-should-know.tsx
@@ -0,0 +1,80 @@
+import type { BlogMeta } from '../index';
+
+export const meta: BlogMeta = {
+ title: 'Walking Your Dog in the Algarve: Hidden Dangers Every Owner Should Know',
+ date: '2024-07-05',
+ description: 'Walking your dog in the Algarve? Learn about hidden dangers like pine processionary caterpillars, grass seeds, heat, and more — plus how to keep your dog safe.',
+ category: 'Tutorial',
+ readTime: '7 min',
+ live: true,
+ image: '/blog-images/walking-your-dog-in-the-algarve-hidden-dangers-every-owner-should-know.webp',
+};
+
+export default function Post() {
+ return (
+ <>
+
Introduction
+
The Algarve is one of the best places in Europe to explore with your dog.
+
Cliffside trails. Quiet forests. Open countryside.
+
But beneath all that beauty, there are a few less obvious risks that many dog owners (especially newcomers) don't see coming.
+
Knowing what to look out for can make the difference between a great walk and an emergency vet visit.
+
+
+
+
1. Pine Processionary Caterpillars (High Risk)
+
These are one of the most dangerous hazards for dogs in Portugal.
+
They appear in:
+
+
Pine forests
+
Woodland trails
+
Warmer months (typically late winter to spring)
+
+
+
Why they're dangerous:
+
Their tiny hairs contain a toxin that can cause:
+
+
Severe swelling of the mouth and tongue
+
Vomiting
+
Difficulty breathing
+
Tissue damage (in serious cases)
+
+
+
What to look for:
+
+
Caterpillars moving in a line (procession)
+
Nests in pine trees (silk-like bundles)
+
+
+
+
+
2. Grass Seeds (Foxtails)
+
Small, sharp, and incredibly problematic.
+
They're common in:
+
+
Dry grasslands
+
Trail edges
+
Late spring and summer
+
+
+
Why they're dangerous:
+
They can lodge in:
+
+
Noses
+
Ears
+
Eyes
+
Between toes
+
+
+
+
+
Final Thoughts
+
Walking your dog in the Algarve can be one of the best parts of living or visiting here.
- Join thousands of dog owners who are making every walk count. Download the app today!
+ Join thousands of dog owners who are making every walk count. TailTrails is completely free — download it today!
-
- {/* Download Buttons Container */}
-
-
- {/* App Store Active Link */}
-
- {/* Apple SVG Icon */}
-
-
-
Download on the
-
App Store
-
-
- {/* Play Store Disabled / Coming Soon Button */}
-
+ Free
+ 100% free — no subscription, no ads, no catch.
+
diff --git a/src/components/landing/Features.tsx b/src/components/landing/Features.tsx
index 78dabd5..7ebee80 100644
--- a/src/components/landing/Features.tsx
+++ b/src/components/landing/Features.tsx
@@ -28,7 +28,7 @@ const Features = () => {
iconColor: "text-brand"
},
{
- title: "Smart Marching",
+ title: "Smart Matching",
desc: "You tell us about your dog. Our community tags every trail. Then we combine this information - so you can choose where to go with confidence.",
icon: Tag,
size: "md:col-span-8",
diff --git a/src/components/landing/Footer.tsx b/src/components/landing/Footer.tsx
index 6c4e96c..5fabc40 100644
--- a/src/components/landing/Footer.tsx
+++ b/src/components/landing/Footer.tsx
@@ -22,9 +22,9 @@ const Footer = () => {
- {error || 'No articles available yet.'}
+ No articles available yet.
)}
@@ -75,32 +58,32 @@ const BlogList = () => {
- {/** category may be undefined in current setup */}
-
- {(featuredDisplayed as any).category || 'General'}
+
+ {featuredDisplayed.meta.category || 'General'}
Featured
@@ -88,4 +87,4 @@ const BlogPost = () => {
);
};
-export default BlogPost;
+export default BlogPost;
\ No newline at end of file
diff --git a/src/pages/Compare.tsx b/src/pages/Compare.tsx
new file mode 100644
index 0000000..b067fe7
--- /dev/null
+++ b/src/pages/Compare.tsx
@@ -0,0 +1,139 @@
+import { Link } from 'react-router-dom';
+import Header from '@/components/landing/Header';
+import Footer from '@/components/landing/Footer';
+import SEO, { OrganizationSchema, WebSiteSchema, makeBreadcrumbSchema } from '@/components/SEO';
+import { Scale, BarChart3, PawPrint, Map, Heart } from 'lucide-react';
+
+const comparisons = [
+ {
+ slug: 'dog-walking-apps-compared',
+ title: 'Dog Walking & Trail Apps Compared: Which One Actually Fits Your Dog?',
+ excerpt:
+ 'We compared the leading dog walking apps and trail discovery tools — free vs paid, hardware vs phone-only, generic dog-friendly filters vs trails matched to your dog. See the full table.',
+ tag: 'Industry Analysis',
+ icon: BarChart3,
+ image: '/blog-images/how-to-choose-the-right-walk-for-your-dog-based-on-their-personality-and-needs.webp',
+ },
+ {
+ slug: 'tailtrails-vs-wooftrax',
+ title: 'TailTrails vs WoofTrax (Walk for a Dog)',
+ excerpt:
+ 'Both are free apps that record your dog walks. WoofTrax turns walks into shelter donations; TailTrails matches trails to your dog and helps you discover new ones. Which fits you?',
+ tag: 'Free Walk App',
+ icon: PawPrint,
+ },
+ {
+ slug: 'tailtrails-vs-tractive',
+ title: 'TailTrails vs Tractive',
+ excerpt:
+ 'Tractive is a GPS collar for finding a lost dog. TailTrails is a free app for finding the right walk. They solve different problems — here is which you need (and why you might want both).',
+ tag: 'Hardware Tracker',
+ icon: Map,
+ },
+ {
+ slug: 'tailtrails-vs-alltrails',
+ title: 'TailTrails vs AllTrails ("AllTrails for Dogs")',
+ excerpt:
+ 'AllTrails has a "dog-friendly" filter across a huge trail database. TailTrails matches trails to your dog’s energy, behaviour and needs. One is generic, one is personal.',
+ tag: 'Trail Discovery',
+ icon: Map,
+ },
+ {
+ slug: 'tailtrails-vs-fitbark',
+ title: 'TailTrails vs FitBark',
+ excerpt:
+ 'FitBark is a GPS and health collar with a subscription. TailTrails is a free phone app for walk discovery and recording. Different goals, different costs.',
+ tag: 'Hardware Tracker',
+ icon: Heart,
+ },
+ {
+ slug: 'tailtrails-vs-pitpat',
+ title: 'TailTrails vs PitPat',
+ excerpt:
+ 'PitPat is a UK activity and GPS device you wear on the collar. TailTrails is a free app with no hardware. Which suits your dog walking routine?',
+ tag: 'Hardware Tracker',
+ icon: PawPrint,
+ },
+];
+
+const Compare = () => {
+ const featured = comparisons[0];
+ const rest = comparisons.slice(1);
+
+ return (
+
+
+
+
+
+
+
+
Dog Walking App Comparisons
+
+ Not every "dog" app does the same job. Some track your walk, some find your lost dog, some list dog-friendly places.
+ These comparisons help you pick the one that actually fits how you walk your dog.
+
+
+
+
+
+
+
+
+ {featured.tag}
+ Featured
+
+
{featured.title}
+
{featured.excerpt}
+ Read the comparison →
+
+
+
+
+
+
+
+
+
+
+
All Comparisons
+
+ {rest.map((c) => (
+
+
+
+
+
+ {c.tag}
+
+
{c.title}
+
{c.excerpt}
+ Read →
+
+
+
+ ))}
+
+
+
+
+
+
+ );
+};
+
+export default Compare;
\ No newline at end of file
diff --git a/src/pages/Download.tsx b/src/pages/Download.tsx
index e6a13c5..8bb6668 100644
--- a/src/pages/Download.tsx
+++ b/src/pages/Download.tsx
@@ -13,8 +13,12 @@ const Download: React.FC = () => {
window.location.replace(APP_STORE_URL);
} else if (/android/i.test(ua)) {
window.location.replace(PLAY_STORE_URL);
+ } else if (/Macintosh|MacIntel|MacPPC|Mac68K/.test(ua)) {
+ // macOS desktop — send to the App Store (iOS listing)
+ window.location.replace(APP_STORE_URL);
} else {
- window.location.replace(FALLBACK_URL);
+ // Windows / Linux / other desktops — send to Google Play
+ window.location.replace(PLAY_STORE_URL);
}
}, []);
diff --git a/src/pages/FinalizeAccountDeletion.tsx b/src/pages/FinalizeAccountDeletion.tsx
index 48632ea..a27bb35 100644
--- a/src/pages/FinalizeAccountDeletion.tsx
+++ b/src/pages/FinalizeAccountDeletion.tsx
@@ -1,6 +1,7 @@
import * as React from "react";
import { useLocation } from "react-router-dom";
import { toast } from "@/components/ui/use-toast";
+import SEO from "@/components/SEO";
const FinalizeAccountDeletion: React.FC = () => {
const location = useLocation();
@@ -44,6 +45,7 @@ const FinalizeAccountDeletion: React.FC = () => {
return (
+
diff --git a/src/pages/Index.tsx b/src/pages/Index.tsx
index b2a2f32..5eebfd1 100644
--- a/src/pages/Index.tsx
+++ b/src/pages/Index.tsx
@@ -5,10 +5,17 @@ import HowItWorks from "@/components/landing/HowItWorks";
import ProblemSolution from "@/components/landing/ProblemSolution";
import CTA from "@/components/landing/CTA";
import Footer from "@/components/landing/Footer";
+import SEO, { OrganizationSchema, WebSiteSchema, MobileAppSchema } from "@/components/SEO";
const Index = () => {
return (
+
@@ -20,4 +27,4 @@ const Index = () => {
);
};
-export default Index;
+export default Index;
\ No newline at end of file
diff --git a/src/pages/NotFound.tsx b/src/pages/NotFound.tsx
index 7bc2234..d2cd485 100644
--- a/src/pages/NotFound.tsx
+++ b/src/pages/NotFound.tsx
@@ -1,5 +1,6 @@
import { useLocation } from "react-router-dom";
import { useEffect } from "react";
+import SEO from "@/components/SEO";
const NotFound = () => {
const location = useLocation();
@@ -10,6 +11,7 @@ const NotFound = () => {
return (
+
404
Oops! Page not found
diff --git a/src/pages/Privacy.tsx b/src/pages/Privacy.tsx
index 3d4a17d..c6042e7 100644
--- a/src/pages/Privacy.tsx
+++ b/src/pages/Privacy.tsx
@@ -1,8 +1,10 @@
import React from "react";
+import SEO from "@/components/SEO";
const Privacy: React.FC = () => {
return (
+
Privacy Policy
Last updated: February 13, 2026
diff --git a/src/pages/RequestAccountDeletion.tsx b/src/pages/RequestAccountDeletion.tsx
index 0b1f399..d85aecc 100644
--- a/src/pages/RequestAccountDeletion.tsx
+++ b/src/pages/RequestAccountDeletion.tsx
@@ -1,5 +1,6 @@
import * as React from "react";
import { toast } from "@/components/ui/use-toast";
+import SEO from "@/components/SEO";
const RequestAccountDeletion: React.FC = () => {
const [email, setEmail] = React.useState("");
@@ -40,6 +41,7 @@ const RequestAccountDeletion: React.FC = () => {
return (
+
diff --git a/src/pages/Terms.tsx b/src/pages/Terms.tsx
index 65430e1..11a6def 100644
--- a/src/pages/Terms.tsx
+++ b/src/pages/Terms.tsx
@@ -1,8 +1,10 @@
import React from "react";
+import SEO from "@/components/SEO";
const Terms: React.FC = () => {
return (
Be the first to know as soon as the TailTrails App is live
-
-
-
-
-
-
-
-
-
TailTrails
-
Find trails tailored to your dog
-
-
-
-
-
-
-
-
-
-
-
-
-
-
- );
-};
-
-export default Waitlist;
diff --git a/src/pages/compare/dog-walking-apps-compared.tsx b/src/pages/compare/dog-walking-apps-compared.tsx
new file mode 100644
index 0000000..8caa0e0
--- /dev/null
+++ b/src/pages/compare/dog-walking-apps-compared.tsx
@@ -0,0 +1,184 @@
+import { Link } from 'react-router-dom';
+import Header from '@/components/landing/Header';
+import Footer from '@/components/landing/Footer';
+import SEO, { OrganizationSchema, makeBreadcrumbSchema, makeFAQSchema } from '@/components/SEO';
+import '../blog.css';
+
+// Honest, defensible comparison. ✓ = yes, — = no, ~ = partial / paid.
+const rows = [
+ { name: 'TailTrails', type: 'Phone app', free: '✓ Free', hardware: '— None', record: '✓ GPS', discover: '✓ Matched to your dog', community: '✓ Shared trails', sub: '— None' },
+ { name: 'WoofTrax', type: 'Phone app', free: '✓ Free (ads)', hardware: '— None', record: '✓ GPS', discover: '— No', community: '~ Groups', sub: '— None' },
+ { name: 'Tractive', type: 'GPS collar', free: '~ Paid', hardware: '✓ Collar + sub', record: '~ Walk feature', discover: '— No', community: '~ Family sharing', sub: '✓ Monthly' },
+ { name: 'PitPat', type: 'Activity / GPS device', free: '~ Paid', hardware: '✓ Device', record: '~ Activity', discover: '— No', community: '~ Family', sub: '~ Optional' },
+ { name: 'FitBark', type: 'GPS / health collar', free: '~ Paid', hardware: '✓ Collar + sub', record: '~ Walk feature', discover: '— No', community: '~ Journal', sub: '✓ Monthly' },
+ { name: 'AllTrails', type: 'Trail app', free: '~ Freemium', hardware: '— None', record: '✓ GPS', discover: '~ "Dog-friendly" filter', community: '✓ Reviews', sub: '✓ Optional' },
+ { name: 'BringFido', type: 'Places directory', free: '✓ Free', hardware: '— None', record: '— No', discover: '~ Dog-friendly places', community: '✓ Reviews', sub: '— None' },
+ { name: 'Sniffspot', type: 'Private rentals', free: '~ Pay per visit', hardware: '— None', record: '— No', discover: '~ Private spaces', community: '~ Host reviews', sub: '— None' },
+];
+
+// Mobile cards show the most decision-relevant fields.
+const cardFields = [
+ { key: 'free', label: 'Cost' },
+ { key: 'hardware', label: 'Hardware' },
+ { key: 'record', label: 'Records walks' },
+ { key: 'discover', label: 'Trail discovery' },
+ { key: 'sub', label: 'Subscription' },
+] as const;
+
+const faqs = [
+ { q: 'What is the best free dog walking app?', a: 'It depends on your goal. WoofTrax is great if you want your walks to support a shelter. TailTrails is the stronger choice if you want to discover new trails that actually suit your dog, not just record the ones you already do. Both are free.' },
+ { q: 'Is TailTrails a GPS pet tracker?', a: 'No. TailTrails records your walks using your phone’s GPS and helps you find trails matched to your dog. It does not track your dog’s live location when off the lead. For a lost-dog scenario you want a GPS collar like Tractive, PitPat or FitBark.' },
+ { q: 'Can I use TailTrails instead of a GPS collar?', a: 'For walk discovery and recording, yes. For escape recovery, no — those are different problems. Many owners use a free walk app like TailTrails day to day and a GPS collar only for dogs that bolt.' },
+ { q: 'Is AllTrails good for dogs?', a: 'AllTrails has a "dog-friendly" filter and a huge trail database, but it does not know anything about your specific dog. A trail being dog-friendly does not mean it suits a reactive, high-energy or older dog. TailTrails matches trails to your dog’s traits.' },
+ { q: 'Do these apps require a subscription?', a: 'TailTrails and WoofTrax are free. AllTrails is free with paid tiers for offline maps. Tractive and FitBark require a subscription because they use cellular hardware. PitPat offers a no-subscription option.' },
+];
+
+const BigComparison = () => {
+ return (
+
+
+
+
+
+
+ {/* Wider than the default article column so the 8-column table breathes. */}
+
+
Dog Walking & Trail Apps Compared
+
+ The "dog app" category is confusing because the apps do very different things. Some record your walk.
+ Some find a lost dog. Some list dog-friendly places. This table puts them side by side so you can see
+ which problem each one actually solves — and which one fits how you walk your dog.
+
+
+ {/* Mobile: stacked cards instead of a cramped, scrolling table. */}
+
+ {rows.map((r) => (
+
+
+ {r.name}
+ {r.type}
+
+
+ {cardFields.map(({ key, label }) => (
+
+
{label}
+
{(r as any)[key]}
+
+ ))}
+
+
+ ))}
+
+
+
Three different problems — do not confuse them
+
Most "dog app" searches actually fall into one of three needs:
+
+
Record my walks — a free phone app like TailTrails or WoofTrax. No hardware, no subscription.
+
Find my lost dog — a GPS collar like Tractive, PitPat or FitBark. Hardware + (usually) a subscription.
+
Find somewhere to go — a trail or places app like AllTrails, BringFido or Sniffspot.
+
+
+ TailTrails is the only app in this list that does the first and the third together — and crucially,
+ it matches trails to your dog, not just a generic "dog-friendly" label. A trail can be dog-friendly
+ and still be wrong for a reactive, high-energy or older dog. That match is the difference between a good walk
+ and a stressful one.
+
+
+
Why "dog-friendly" is not enough
+
+ A beach that allows dogs, a forest that allows dogs, a park that allows dogs — these are all "dog-friendly."
+ But a reactive dog needs space and low traffic, a high-energy dog needs open ground to run, and an older dog
+ needs flat, shaded terrain. Generic filters cannot tell you that. TailTrails uses community tags
+ (environment, terrain, traffic, exposure) combined with your dog’s profile to suggest walks that bring out
+ the best in your dog. Read more in our article on
+ {' '}choosing the right walk for your dog.
+
+
+
Free vs paid: what you actually spend
+
+ TailTrails and WoofTrax are free. AllTrails is free to browse but pushes a paid tier for offline maps and
+ wrong-turn alerts. The hardware trackers (Tractive, FitBark) require a subscription — the device is unusable
+ without it — so the real cost is the device plus years of monthly fees. If your goal is better walks rather
+ than lost-dog recovery, a free app covers it.
+
+
+
The honest verdict
+
+ There is no single winner because the apps solve different problems. If you want to find new walks that
+ suit your dog and record them for free, TailTrails is built for that. If your dog is an escape risk,
+ add a GPS collar. If you just want to support a shelter with your daily walk, WoofTrax is lovely. Use the
+ table above to pick the one that matches your actual need.
+
+
+
+
Read the individual comparisons
+
+
TailTrails vs WoofTrax →
+
TailTrails vs Tractive →
+
TailTrails vs AllTrails →
+
TailTrails vs FitBark →
+
TailTrails vs PitPat →
+
+
+
+ ← Back to all comparisons
+
+
+
+
+
+
+
+ );
+};
+
+export default BigComparison;
\ No newline at end of file
diff --git a/src/pages/compare/tailtrails-vs-alltrails.tsx b/src/pages/compare/tailtrails-vs-alltrails.tsx
new file mode 100644
index 0000000..f3a2cdb
--- /dev/null
+++ b/src/pages/compare/tailtrails-vs-alltrails.tsx
@@ -0,0 +1,88 @@
+import { Link } from 'react-router-dom';
+import Header from '@/components/landing/Header';
+import Footer from '@/components/landing/Footer';
+import SEO, { makeComparisonSchema } from '@/components/SEO';
+import '../blog.css';
+
+const TailtrailsVsAlltrails = () => (
+
+
+
+
+
+
+
TailTrails vs AllTrails ("AllTrails for Dogs")
+
+ "Is there an AllTrails for dogs?" is one of the most common questions from dog owners who hike. AllTrails is the
+ biggest trail app in the world and it does have a dog-friendly filter. TailTrails is dog-first and dog-only. The
+ difference sounds small until you actually use them — then it is the difference between "allowed" and "right."
+
+
+
+
What AllTrails does well
+
+ AllTrails has an enormous trail database, great search filters (distance, elevation, difficulty, trail type), photos,
+ reviews, and GPS recording. The "dogs allowed" filter narrows it to trails where dogs are permitted. For general
+ hiking it is excellent, and if you already use it, the dog filter is a reasonable way to shortlist routes.
+
+ A trail being dog-friendly just means dogs are allowed. It says nothing about whether it suits your
+ dog. A narrow cliff path is dog-friendly but wrong for a reactive dog that needs space. A busy popular hike is
+ dog-friendly but hellish for a nervous rescue. A long exposed ridge is dog-friendly but dangerous for a brachycephalic
+ breed in summer. AllTrails’ filter cannot see any of that.
+
+
+ This is exactly the problem TailTrails is built to solve — and the idea behind our article on
+ {' '}why "dog-friendly" isn’t enough.
+
+
+
What TailTrails does instead
+
+ TailTrails tags every trail with the things that actually decide whether a walk goes well — environment, terrain,
+ traffic, exposure, shade — and combines that with a profile of your dog (energy, sociability, confidence,
+ sensitivities). The result is a shortlist of walks that bring out the best in your dog, not just a list of places
+ dogs are tolerated. It also records your walks and lets you save and revisit favourites.
+
+
TailTrails is the stronger choice if:
+
+
Your dog has specific needs (reactive, high-energy, older, sensitive)
+
You want trail suggestions, not just a filter on a database
+
You want a dog-first community, not a general hiking app with a dog tag
+
+
+
Cost and offline
+
+ AllTrails is free to browse but gates offline maps, wrong-turn alerts and 3D previews behind a paid subscription.
+ TailTrails is free. If your main use is finding the right dog walk near you rather than backcountry navigation,
+ the free tier of TailTrails covers it without an upsell.
+
+
+
Which should you pick?
+
Choose AllTrails if you are a serious hiker first and a dog owner second, and you want the biggest trail catalogue with a dog filter on top.
+
Choose TailTrails if the dog is the point — you want walks chosen because they suit your dog, not just because dogs are allowed.
+
+
+
+ ← Back to all comparisons
+
+
+
+
+
+
+);
+
+export default TailtrailsVsAlltrails;
\ No newline at end of file
diff --git a/src/pages/compare/tailtrails-vs-fitbark.tsx b/src/pages/compare/tailtrails-vs-fitbark.tsx
new file mode 100644
index 0000000..e0c7420
--- /dev/null
+++ b/src/pages/compare/tailtrails-vs-fitbark.tsx
@@ -0,0 +1,80 @@
+import { Link } from 'react-router-dom';
+import Header from '@/components/landing/Header';
+import Footer from '@/components/landing/Footer';
+import SEO, { makeComparisonSchema } from '@/components/SEO';
+import '../blog.css';
+
+const TailtrailsVsFitbark = () => (
+
+
+
+
+
+
+
TailTrails vs FitBark
+
+ FitBark and TailTrails both live on a dog owner’s phone, but they come at the same question from opposite ends.
+ FitBark sells you a collar and a subscription to monitor your dog’s location, activity and health. TailTrails is a
+ free app that helps you find and record the right walks. One is a health-and-safety device; the other is a walking
+ companion.
+
+
+
+
What FitBark is built for
+
+ FitBark is a GPS and activity collar (plus a mandatory subscription for the cellular service). It tracks live
+ location, escape alerts from “Safe Places”, location history, activity, sleep quality, and a Health Index it uses
+ to flag early signs of illness or anxiety. It is used by owners and vets, and it integrates with Apple Health,
+ Google Fit and Fitbit. It is a serious health-monitoring device.
+
+
FitBark is the right choice if your priority is:
+
+
Continuous health, sleep and activity monitoring for your dog
+
Live GPS location and escape alerts
+
Sharing data with a vet, trainer or dog walker
+
+
+
What TailTrails is built for
+
+ TailTrails does not monitor your dog’s body and it cannot find a lost dog. What it does is answer the question
+ FitBark never asks: where should I walk my dog today? It suggests trails matched to your dog’s
+ energy, behaviour and needs using community tags, records your walks with GPS, and lets you save and revisit
+ favourites. No collar, no subscription.
+
+
TailTrails is the stronger choice if your priority is:
+
+
Discovering new walks that suit your dog, not just logging them
+
A free app with no hardware or ongoing cost
+
A dog-first community sharing trails and routes
+
+
+
The cost gap
+
+ FitBark requires a device purchase and a subscription — the collar’s tracking features do not work without it.
+ Over a few years that is a meaningful ongoing cost, and it buys safety and health insight, not walk discovery.
+ TailTrails is free. If your dog is healthy and not an escape risk, you are paying FitBark for capabilities you may
+ not need.
+
+
+
Which should you pick?
+
Choose FitBark if you want health and location monitoring for your dog, especially an older, anxious or escape-prone dog.
+
Choose TailTrails if you want to find better walks for your dog and record them, for free.
+
They pair well: FitBark to keep tabs on your dog’s wellbeing, TailTrails to actually decide where the two of you go.
+
+
+
+ ← Back to all comparisons
+
+
+
+
+
+
+);
+
+export default TailtrailsVsFitbark;
\ No newline at end of file
diff --git a/src/pages/compare/tailtrails-vs-pitpat.tsx b/src/pages/compare/tailtrails-vs-pitpat.tsx
new file mode 100644
index 0000000..9a49010
--- /dev/null
+++ b/src/pages/compare/tailtrails-vs-pitpat.tsx
@@ -0,0 +1,78 @@
+import { Link } from 'react-router-dom';
+import Header from '@/components/landing/Header';
+import Footer from '@/components/landing/Footer';
+import SEO, { makeComparisonSchema } from '@/components/SEO';
+import '../blog.css';
+
+const TailtrailsVsPitpat = () => (
+
+
+
+
+
+
+
TailTrails vs PitPat
+
+ PitPat is a popular UK-made device that clips to your dog’s collar and tracks activity (and, on the GPS model,
+ location). TailTrails is a free phone app that helps you find and record walks. Like the other hardware trackers,
+ PitPat and TailTrails solve different problems — and the device-vs-app distinction matters for your wallet.
+
+
+
+
What PitPat is built for
+
+ PitPat’s strength is exercise and activity data. Its activity monitor tracks daily movement, calories, rest and
+ breed-specific exercise goals, with a battery that lasts months. The PitPat GPS model adds location tracking with a
+ no-subscription option — pay once, no monthly fee — which is unusual in this category. It is a tidy,
+ low-running-cost way to know how much exercise your dog is actually getting.
+
+
PitPat is the right choice if you want:
+
+
Long-term activity and exercise data for your dog
+
A no-subscription GPS option (on the GPS model)
+
A “how much is my dog moving?” answer rather than a “where should we walk?” one
+
+
+
What TailTrails is built for
+
+ PitPat tells you how much your dog exercised. It does not tell you where to take them — it records activity, not
+ routes you might enjoy, and it does not match trails to your dog’s temperament. TailTrails fills that gap: it
+ suggests walks suited to your dog’s energy, behaviour and sensitivities, records them with your phone’s GPS, and
+ lets you save favourites. No device, no collar, no subscription.
+
+
TailTrails is the stronger choice if you want:
+
+
Trail ideas matched to your dog, not just an activity total
+
A free app with nothing to charge or attach
+
Variety in your walking routine
+
+
+
The cost and friction difference
+
+ Even PitPat’s no-subscription GPS is still a device you buy, charge (or replace the battery on), and keep attached
+ to the collar. TailTrails is an app you already have everything you need to use — your phone. If your goal is
+ better walks rather than measured exercise, the device adds cost and chores without helping with the decision.
+
+
+
Which should you pick?
+
Choose PitPat if you want to know how much exercise your dog is getting, or a no-monthly-fee GPS for peace of mind.
+
Choose TailTrails if you want to find new walks that suit your dog and record them, for free.
+
They are complementary: PitPat quantifies your dog’s day, TailTrails decides where that day happens.
+
+
+
+ ← Back to all comparisons
+
+
+
+
+
+
+);
+
+export default TailtrailsVsPitpat;
\ No newline at end of file
diff --git a/src/pages/compare/tailtrails-vs-tractive.tsx b/src/pages/compare/tailtrails-vs-tractive.tsx
new file mode 100644
index 0000000..fd520b3
--- /dev/null
+++ b/src/pages/compare/tailtrails-vs-tractive.tsx
@@ -0,0 +1,91 @@
+import { Link } from 'react-router-dom';
+import Header from '@/components/landing/Header';
+import Footer from '@/components/landing/Footer';
+import SEO, { makeComparisonSchema } from '@/components/SEO';
+import '../blog.css';
+
+const TailtrailsVsTractive = () => (
+
+
+
+
+
+
+
TailTrails vs Tractive
+
+ TailTrails and Tractive both show up when you search for "dog walking app," but they solve completely different
+ problems. Confusing them is the most common — and most expensive — mistake in this category. Here is the short
+ version: Tractive tells you where your dog is. TailTrails tells you where to walk your dog.
+
+
+
+
The fundamental difference
+
+ Tractive is a GPS collar plus a mandatory subscription. Its job is live location: real-time tracking,
+ geofence escape alerts, and location history. It also has a "Walk" feature that records your route using your phone’s
+ GPS (the standalone Tractive Dog Walk app has been retired and folded into the main app). But make no mistake —
+ Tractive is a safety device first.
+
+
+ TailTrails is a free phone app. Its job is walk discovery: it suggests trails matched to your dog’s
+ traits, records your walks, and lets you save and share routes. It has no view of where your dog is when off the lead.
+ It is an everyday-walking app first.
+
+
+
Where Tractive is strong
+
+ If your dog has ever bolted, slips the lead, or you walk in open countryside where they vanish out of sight, Tractive
+ is excellent — live updates every couple of seconds and instant alerts when they leave a safe zone. That peace of
+ mind is what you are paying for. Its activity and sleep tracking is a nice secondary benefit.
+
+
Tractive is the right call if your real worry is:
+
+
"My dog might get lost or escape"
+
You walk off-lead in remote or open areas
+
You want escape alerts, not walk ideas
+
+
+
Where TailTrails is different
+
+ Tractive will not tell you which trail suits a reactive dog, where the quiet forest paths are, or which beach is low
+ traffic at this time of year. It records a walk you already decided to do; it does not help you decide. And it costs
+ money every month — the collar is useless without the subscription.
+
+
+ TailTrails is free, needs no hardware, and is built around the decision Tractive does not help with: where
+ should I take my dog today? It matches trails to your dog’s profile so you stop defaulting to the same
+ route, and it records the walk once you are out.
+
+
+
The cost reality
+
+ TailTrails is free. Tractive is a device purchase plus an ongoing subscription — over two or three years that adds
+ up considerably. That cost buys safety features, not discovery. If lost-dog recovery is not your concern, you are
+ paying for capability you may not use.
+
+
+
Which should you pick?
+
Choose Tractive if your dog is an escape risk or you need live location and escape alerts.
+
Choose TailTrails if you want to find and record better walks for your dog, for free.
+
+ Many owners genuinely benefit from both: a GPS collar for safety on off-lead adventures, and a free app like
+ TailTrails to actually decide where those adventures happen. They are complementary, not competitors.
+
+
+
+
+ ← Back to all comparisons
+
+
+
+
+
+
+);
+
+export default TailtrailsVsTractive;
\ No newline at end of file
diff --git a/src/pages/compare/tailtrails-vs-wooftrax.tsx b/src/pages/compare/tailtrails-vs-wooftrax.tsx
new file mode 100644
index 0000000..6804b5e
--- /dev/null
+++ b/src/pages/compare/tailtrails-vs-wooftrax.tsx
@@ -0,0 +1,90 @@
+import { Link } from 'react-router-dom';
+import Header from '@/components/landing/Header';
+import Footer from '@/components/landing/Footer';
+import SEO, { makeComparisonSchema } from '@/components/SEO';
+import '../blog.css';
+
+const TailtrailsVsWooftrax = () => (
+
+
+
+
+
+
+
TailTrails vs WoofTrax (Walk for a Dog)
+
+ TailTrails and WoofTrax are both free phone apps that record your dog walks with GPS — no hardware, no subscription.
+ They are the two most natural alternatives if you want a simple "track my dog walk" app. But they are built around
+ very different ideas about what a dog walk is for.
+
+
+
+
What each app is built around
+
+ WoofTrax (Walk for a Dog) is built around charity. Every walk you log earns donations for the animal
+ shelter or rescue of your choice, funded by sponsors and advertising. The walk itself is recorded — distance,
+ duration, route — and you can join groups and challenges. The mission is getting more people walking so more
+ money reaches shelters.
+
+
+ TailTrails is built around discovery. It also records your walks (distance, duration, route, photos),
+ but its core idea is that the same daily walk gets boring and that most "dog-friendly" places are not actually
+ right for your dog. So it suggests new trails matched to your dog’s energy, behaviour and needs, using community
+ tags for environment, terrain, traffic and exposure.
+
+
+
Where WoofTrax is strong
+
+ WoofTrax has been around a long time and has logged a huge number of walks for a huge number of charities. If you
+ already walk your dog the same routes every day and simply want that habit to do some good, it is hard to argue with
+ — you press start, you walk, a shelter benefits. The groups and challenges add a nice social layer, and the app
+ is genuinely free.
+
+
WoofTrax is a great fit if you want:
+
+
To support a specific shelter or rescue with your daily walk
+
Group walking challenges with friends or a community
+
A straightforward walk log without much decision-making
+
+
+
Where TailTrails is different
+
+ The gap WoofTrax does not fill is "where should I walk today?" It records where you went, but it does
+ not help you find a new place that suits your dog. If your reactive dog needs a quiet trail, or your spaniel needs
+ open space to run, WoofTrax cannot tell you which routes to try.
+
+
+ TailTrails does. Every trail is tagged by the community, every dog has a profile, and the app brings the two together
+ so you can choose with confidence instead of guessing. You can also save trails and follow them again. It is the
+ stronger choice if variety and the right environment matter to you and your dog.
+
+
+
Potential downsides of each
+
+ WoofTrax is ad-funded, which some owners find intrusive, and its trail discovery is effectively non-existent.
+ TailTrails is newer, so its community trail coverage is still growing in regions outside its launch areas — the
+ more people use it and tag trails, the better the matching gets.
+
+
+
Which should you pick?
+
Choose WoofTrax if your main motivation is supporting a shelter with walks you already do.
+
Choose TailTrails if you want to discover new walks that genuinely suit your dog, not just log the ones you already know.
+
And nothing stops you using both — but if you had to pick one for everyday use, it comes down to charity vs discovery.
+
+
+
+ ← Back to all comparisons
+
+
+
+
+
+
+);
+
+export default TailtrailsVsWooftrax;
\ No newline at end of file