Page Types: Query Pages vs Search Pages vs Product Pages
This article explains the three types of pages on our website and how they differ in purpose, URL structure, content generation, and SEO strategy.
The Three Page Types
1. Query Pages (/q/<slug>)
Purpose: Pre-generated pages for common search queries
Example: /q/mini-pc-for-office
Content: Static HTML with AI-generated descriptions, pre-filtered product list
SEO: Optimized for specific search terms, indexed by Google
2. Search Pages (/q/?q=<query>)
Purpose: Dynamic search results for any query
Example: /q/?q=fanless+computer
Content: Real-time search results, no pre-generated content
SEO: Not indexed (noindex), for user exploration
3. Product Pages (/p/<sku>)
Purpose: Detailed specifications for a specific product
Example: /p/Treo-N100-8-256-2H-W6-11P
Content: Product name, images, features, datasheet, pricing
SEO: Indexed, optimized for product-specific searches
Query Pages: Pre-Generated SEO Pages
URL Structure
/q/<slug>
/q/<slug>?<filters>
Slug: Hyphenated query text (e.g., mini-pc-for-office)
Filters: URL parameters for dynamic filtering (e.g., ?Cores=4&Main+Memory=8)
Data Source
Query pages are stored in DynamoDB (QueryPageV3 table):
qp = QueryPageV3.get(slug)
Fields:
-
slug: Primary key (e.g., "mini-pc-for-office") -
title: Display title -
skus: List of matching product SKUs (top 100) -
filters: Base filters applied to products -
descriptions: AI-generated content per language -
is_active: Whether page is live
Content Generation
Content is generated by AI (DeepSeek) and cached:
Process:
- Check if content exists for language
- If missing and page is active, generate or queue
- Fallback to English if localized content missing
- Convert Markdown to HTML at render time
# Check cached content
query_descriptions = qp.descriptions.as_dict()
md_content = query_descriptions.get(language, {}).get("content", "")
# ... (implementation details omitted)
Dynamic Filtering
Users can apply filters via URL parameters:
Base filters (from database): {"Form Factor": "Mini PC"}
User filters (from URL): ?Cores=4&Main+Memory=8
Active filters (merged): {"Form Factor": "Mini PC", "Cores": 4, "Main Memory": 8}
Empty string values remove filters:
/q/mini-pc?Cores= # Removes Cores filter
Product Listing
Products are pre-filtered and cached in the database:
matching_skus = list(qp.skus) # Top 100 SKUs
# Filter to accessories=0 if too many (reduces variations)
# ... (implementation details omitted)
Related Searches
Related searches are fetched from search service:
response = requests.get(
"http://manage.thinvent.in:5000/api/related",
params={"q": title, "limit": 8},
timeout=2
)
related_searches = [(item["query"], f"/q/?q={item['query']}")
for item in data.get("queries", [])]
Facets
Facets (filter options with counts) are computed dynamically:
from app.shared.filter_service import filter_skus_and_get_facets
result = filter_skus_and_get_facets(active_filters)
facets_with_counts = result.get("facets", {})
Search Pages: Dynamic Query Results
URL Structure
/q/?q=<query>
/q/?q=<query>&<filters>
Query parameter: User's search text (e.g., ?q=fanless+computer)
Filters: Same as query pages
Fallback Behavior
If slug is unknown, query page falls back to search:
def query_page(slug: str = None):
if slug is None:
return search_products()
qp = QueryPageV3.get(slug)
if not qp:
# Unknown slug → search
return search_products(search_query=slug.replace("-", " "))
Real-Time Search
Search pages call the search service for live results:
def search_products(search_query: str = None):
# Get query from URL or parameter
query = request.args.get("q") or search_query
# ... (implementation details omitted)
No Pre-Generated Content
Search pages have no AI-generated descriptions:
-
Generic meta description
-
No cached content
-
No SEO optimization
SEO Strategy
Search pages are not indexed:
<meta name="robots" content="noindex, follow">
Why? Avoid duplicate content with query pages.
Product Pages: Detailed Specifications
URL Structure
/p/<sku>
SKU: Hyphen-separated product identifier (e.g., Treo-N100-8-256-2H-W6-11P)
Content
Product pages show:
Product name: Expanded from SKU structure
name = expand_sku(sku) # "Thinvent® Treo Mini PC with Intel® N100..."
Images: Product photos and videos
images = do_pics(sku) # [(name, url), ...]
Features: Extracted from SKU components
features = product_features(sku)
# {"Processing": {"Cores": "4", "Max Frequency": "3.4 GHz"}, ...}
Description: AI-generated tagline and body
desc = ProductDescription.get(sku, language)
tagline = desc.tagline
body = desc.body
Pricing: Shown if user came from Google Shopping
show_price = session.get("from_google_shopping") or \
request.cookies.get("show_pricing") == "1"
Datasheet: PDF download link
/gs/<sku> # Generates PDF on-demand
SEO Optimization
Product pages are fully indexed:
-
Unique title per SKU
-
Meta description from AI
-
Structured data (JSON-LD)
-
Canonical URL
Comparison Table
| Feature | Query Pages | Search Pages | Product Pages |
|---|---|---|---|
| URL | /q/<slug> |
/q/?q=<query> |
/p/<sku> |
| Content | Pre-generated AI | None | Product specs |
| Products | Pre-filtered list | Live search results | Single product |
| Filters | Yes (URL params) | Yes (URL params) | No |
| SEO | Indexed | Not indexed | Indexed |
| Caching | Database + CDN | No cache | CDN only |
| Related | Yes (8 queries) | Yes (8 queries) | No |
| Facets | Yes (dynamic) | Yes (dynamic) | No |
Data Flow
graph TD
User[User Search]
User -->|Known query| QP[Query Page
/q/mini-pc]
User -->|Unknown query| SP[Search Page
/q/?q=fanless]
User -->|Product click| PP[Product Page
/p/Treo-N100-8-256]
QP --> DB[(QueryPageV3
DynamoDB)]
QP --> AI[AI Content
DeepSeek]
QP --> SS[Search Service
Related queries]
SP --> SS
PP --> PDB[(ProductDescription
DynamoDB)]
PP --> SKU[SKU Expansion
Features]Interlinking Strategy
Query → Product
Query pages link to products:
<a href="/p/{{ sku }}">{{ product_name }}</a>
Product → Query
Product pages link to relevant query pages:
<a href="/q/mini-pc">Browse all Mini PCs</a>
Query → Query
Related searches link to other query pages:
<a href="/q/fanless-mini-pc">Fanless Mini PC</a>
Search → Query
If search query matches a known slug, redirect:
if slug_exists(query):
return redirect(f"/q/{query}")
Caching Strategy
Query Pages
Database: Content cached in DynamoDB
CDN: Full page cached by CloudFront (1 hour TTL)
Invalidation: Manual (when content updated)
Search Pages
No caching: Always fresh results
Product Pages
CDN: Full page cached by CloudFront (1 hour TTL)
Invalidation: Manual (when product updated)
References
Related Articles
-
SEO Pipeline Overview - How query pages are generated
-
Content AI Generation - DeepSeek descriptions
-
Search Service Architecture - Live search
-
SKU Structure - Product identifiers
-
Feature Extraction - Product specifications
Summary
Three page types serve different purposes:
Query Pages (/q/<slug>):
-
✅ Pre-generated for common searches
-
✅ AI-generated content
-
✅ Pre-filtered products (top 100)
-
✅ Dynamic filtering via URL
-
✅ SEO optimized (indexed)
-
✅ Related searches and facets
Search Pages (/q/?q=<query>):
-
✅ Real-time search results
-
✅ No pre-generated content
-
✅ Live search service call
-
✅ Not indexed (noindex)
-
✅ Fallback for unknown queries
Product Pages (/p/<sku>):
-
✅ Detailed specifications
-
✅ AI-generated descriptions
-
✅ Feature extraction from SKU
-
✅ Images and datasheet
-
✅ SEO optimized (indexed)
-
✅ Conditional pricing
This three-tier architecture balances SEO (query pages), user exploration (search pages), and product details (product pages).