---
title: Recent articles by category
slug: graph/docs/recent-articles-by-category
docTags: 
createdAt: 2026-07-30T20:30:17.955Z
---

Use Optimizely Graph queries to retrieve and display recent articles based on category filters. These examples let you build dynamic content experiences and suggest related articles to your users.

## Basic category-based article query

Use this query to fetch the most recent articles from a specific category. This is ideal for showing topic-based content or suggesting related articles.

The following query retrieves up to 10 articles from a specified category and filters for published content, and sorts results by publish date, showing the newest first:

```graphql
# This query retrieves up to 10 articles from a specified category.
# It filters for published content and sorts results by publish date (newest first).

query GetRecentArticlesByCategory($category: String, $limit: Int = 10) {
  ArticlePage(
    where: {
      Category: { Name: { eq: $category } }
      StartPublish: { lte: "2025-09-14T23:59:59Z" }
    }
    orderBy: { StartPublish: DESC }
    limit: $limit
  ) {
    total
    items {
      Name
      RelativePath
      TeaserText
      MainBody
      StartPublish
      PageImage {
        Url
      }
      Category {
        Name
      }
    }
  }
}
```

## Advanced category filtering with time ranges

Use the following query to filter articles by multiple categories within a specific date range, making it ideal for time-sensitive content or analytics:

```graphql
# This query retrieves articles from selected categories within a defined time range.
# It returns article details and category facets for filtering and analysis.

query GetArticlesByCategoryAndTimeRange(
  $categories: [String!],
  $startDate: Date!,
  $endDate: Date!,
  $limit: Int = 20
) {
  ArticlePage(
    where: {
      _and: [
        { StartPublish: { gte: $startDate, lte: $endDate } }
      ]
    }
    orderBy: { StartPublish: DESC }
    limit: $limit
  ) {
    total
    facets {
      Category {
        Name(filters: $categories) {
          name
          count
        }
      }
    }
    items {
      Name
      RelativePath
      TeaserText
      MainBody
      StartPublish
      PageImage {
        Url
      }
      Category {
        Name
        Description
      }
    }
  }
}
```

### React implementation

Use the following query to filter articles by multiple categories within a specific date range, making it ideal for time-sensitive content or analytics:

```typescript
// This component fetches and displays articles based on the selected category.
// It includes loading and error states, and lets users change category and article count.

import { gql, useQuery } from '@apollo/client';
import { useState } from 'react';

const GET_ARTICLES_BY_CATEGORY = gql`
  query GetRecentArticlesByCategory($category: String, $limit: Int = 10) {
    ArticlePage(
      where: {
        Category: { Name: { eq: $category } }
        StartPublish: { lte: "2025-09-14T23:59:59Z" }
      }
      orderBy: { StartPublish: DESC }
      limit: $limit
    ) {
      total
      items {
        Name
        RelativePath
        TeaserText
        MainBody
        StartPublish
        PageImage {
          Url
        }
        Category {
          Name
        }
      }
    }
  }
`;

interface Article {
  Name: string;
  RelativePath: string;
  TeaserText?: string;
  MainBody?: string;
  StartPublish: string;
  PageImage?: {
    Url: string;
  };
  Category?: {
    Name: string;
  };
}

export function ArticlesByCategory() {
  const [selectedCategory, setSelectedCategory] = useState<string>('technology');
  const [limit, setLimit] = useState(10);

  const { loading, error, data, refetch } = useQuery(GET_ARTICLES_BY_CATEGORY, {
    variables: { category: selectedCategory, limit },
    errorPolicy: 'partial'
  });

  const handleCategoryChange = (category: string) => {
    setSelectedCategory(category);
  };

  if (loading) return (
    <div className="loading-state">
      <div className="spinner"></div>
      <p>Loading articles...</p>
    </div>
  );

  if (error) return (
    <div className="error-state">
      <h3>Unable to load articles</h3>
      <p>{error.message}</p>
      <button onClick={() => refetch()}>Try Again</button>
    </div>
  );

  const articles: Article[] = data?.ArticlePage?.items || [];

  return (
    <div className="articles-by-category">
      <div className="filter-controls">
        <h2>Articles by Category</h2>
        <div className="category-filters">
          {['technology', 'innovation', 'development', 'design', 'business'].map(category => (
            <label key={category} className="category-filter">
              <input
                type="radio"
                name="category"
                value={category}
                checked={selectedCategory === category}
                onChange={(e) => handleCategoryChange(e.target.value)}
              />
              {category}
            </label>
          ))}
        </div>

        <div className="limit-control">
          <label>
            Show:
            <select value={limit} onChange={(e) => setLimit(Number(e.target.value))}>
              <option value={5}>5 articles</option>
              <option value={10}>10 articles</option>
              <option value={20}>20 articles</option>
            </select>
          </label>
        </div>

        <p className="results-count">
          Found {data?.ArticlePage?.total || 0} articles
        </p>
      </div>

      <div className="articles-grid">
        {articles.map((article) => (
          <article key={article.RelativePath} className="article-card">
            {article.PageImage && (
              <div className="article-image">
                <img 
                  src={article.PageImage.Url} 
                  alt={article.Name}
                />
              </div>
            )}

            <div className="article-content">
              <h3>
                <a href={article.RelativePath}>{article.Name}</a>
              </h3>

              {article.TeaserText && (
                <p className="teaser">{article.TeaserText}</p>
              )}

              <div className="article-meta">
                <time dateTime={article.StartPublish}>
                  {new Date(article.StartPublish).toLocaleDateString()}
                </time>

                {article.Category && (
                  <span className="category">{article.Category.Name}</span>
                )}
              </div>
            </div>
          </article>
        ))}
      </div>
    </div>
  );
}
```
