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:

  1. Check if content exists for language
  2. If missing and page is active, generate or queue
  3. Fallback to English if localized content missing
  4. 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

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).


← Back to Documentation Index