Strapi Troubleshooting: Common Issues and Fixes | OpsBlu Docs

Strapi Troubleshooting: Common Issues and Fixes

Troubleshoot common Strapi-powered site issues including performance problems and tracking failures.

Common issues you may encounter with Strapi-powered sites and how to diagnose and fix them. Since Strapi is a headless CMS, most issues occur in your frontend framework, not in Strapi itself.

Performance Issues

Strapi-powered sites can face unique performance challenges due to their headless architecture, API calls, and frontend framework rendering strategies.

Largest Contentful Paint (LCP)

LCP measures loading performance. Strapi-specific LCP issues include:

  • API response times affecting Time to First Byte (TTFB)
  • Unoptimized images from Strapi media library
  • Framework SSR/SSG rendering delays
  • Multiple API calls blocking initial render
  • Heavy JavaScript bundles in frontend frameworks

Target: LCP under 2.5 seconds

Cumulative Layout Shift (CLS)

CLS measures visual stability. Strapi-specific CLS issues include:

  • Images loaded from Strapi without dimensions
  • Dynamic content causing layout shifts
  • Font loading in Next.js/Gatsby/Nuxt
  • Component hydration shifts
  • Lazy-loaded content from API

Target: CLS under 0.1

General Performance Best Practices

API Optimization:

  • Use Strapi's REST API filtering and field selection
  • Implement GraphQL for precise data fetching
  • Enable Strapi response caching
  • Use CDN for Strapi media files
  • Minimize API calls with proper data fetching strategies

Frontend Framework Optimization:

  • Choose appropriate rendering strategy (SSR/SSG/ISR/CSR)
  • Implement proper caching (SWR, React Query, etc.)
  • Code-split and lazy-load components
  • Optimize bundle size
  • Use modern image formats (WebP, AVIF)

Strapi Configuration:

  • Enable Strapi's response cache plugin
  • Configure media library provider (S3, Cloudinary, etc.)
  • Use Strapi's image optimization features
  • Set up proper database indexes
  • Monitor Strapi server performance

For general performance concepts, see the global performance hub.

Tracking & Analytics Issues

Events Not Firing

Common causes of tracking failures on Strapi-powered sites:

  • SSR/SSG timing issues (scripts running on server)
  • Client-side hydration delays
  • API data not loaded when tracking fires
  • Framework route changes not tracked
  • Missing window/browser checks in tracking code

Common scenarios:

  • GA4 events fire before content data loads
  • Meta Pixel not initialized due to SSR
  • GTM container loads but events don't fire
  • Tracking works on hard refresh but not on client navigation
  • Events fire multiple times due to React re-renders

Framework-Specific Tracking Issues

Next.js:

  • App Router vs Pages Router differences
  • Server Components can't run client-side tracking
  • Route changes not tracked in App Router
  • Middleware affecting tracking scripts

Gatsby:

  • Build-time vs runtime data distinction
  • Page transitions not triggering events
  • Plugin conflicts with tracking

Nuxt.js:

  • SSR hydration affecting pixel initialization
  • Nuxt modules conflicting with tracking
  • Client-side only code running on server

React SPA:

  • Route library integration (React Router, etc.)
  • State management affecting tracking timing
  • Component lifecycle timing

Tracking Best Practices

Framework-Agnostic Principles:

  • Always check for window object before tracking
  • Use useEffect (React) or onMounted (Vue) hooks
  • Implement route change listeners
  • Handle SSR/SSG appropriately
  • Test across rendering methods

Data Availability:

  • Ensure Strapi API data loaded before tracking
  • Use loading states to delay tracking
  • Implement proper error handling
  • Verify API response structure

Testing:

  • Test in development and production builds
  • Test SSR, SSG, and CSR pages separately
  • Use browser extensions (GA Debugger, Pixel Helper, GTM Assistant)
  • Check browser console for errors
  • Verify in analytics platforms (GA4, Meta Events Manager)

For general tracking concepts, see the global troubleshooting hub.

Common Strapi-Specific Issues

API Response Time

Problem: Slow API responses affecting site performance.

Diagnosis:

  • Check Strapi server response times in Network tab
  • Monitor Strapi server metrics
  • Identify slow database queries

Solutions:

  • Enable Strapi's REST cache plugin
  • Optimize database queries and add indexes
  • Use GraphQL to fetch only needed data
  • Implement CDN for API responses
  • Scale Strapi server (vertical or horizontal)
  • Use Strapi's populate parameter strategically

Image Optimization

Problem: Large images from Strapi media library.

Diagnosis:

  • Check image sizes in Network tab
  • Audit Strapi media library
  • Review frontend image implementation

Solutions:

Strapi-side:

// Use Strapi's image service formats
const imageUrl = `${STRAPI_URL}${image.url}?format=webp&width=800&quality=80`;

Frontend-side (Next.js):

// Next.js Image component with Strapi
<Image
  src={`${process.env.NEXT_PUBLIC_STRAPI_URL}${image.url}`}
  width={image.width}
  height={image.height}
  alt={image.alternativeText || ''}
  loader={strapiLoader}
/>

const strapiLoader = ({ src, width, quality }) => {
  return `${src}?format=webp&width=${width}&quality=${quality || 75}`;
};

CORS Errors

Problem: Frontend can't access Strapi API due to CORS.

Diagnosis:

Access to fetch at 'http://localhost:1337/api/articles' from origin 'http://localhost:3000'
has been blocked by CORS policy

Solution:

Update Strapi configuration:

// config/middlewares.js
module.exports = [
  // ...
  {
    name: 'strapi::cors',
    config: {
      enabled: true,
      origin: ['http://localhost:3000', 'https://yourdomain.com'],
      credentials: true,
    },
  },
];

Populate/Relations Issues

Problem: Related data not returned from Strapi API.

Diagnosis:

// Returns: { data: { id: 1, attributes: { title: 'Article', category: {} } } }
// Expected: Full category data

Solution:

// Use populate parameter
fetch(`${STRAPI_URL}/api/articles/${id}?populate=*`)

// Or populate specific fields
fetch(`${STRAPI_URL}/api/articles/${id}?populate[category]=*&populate[author][populate][avatar]=*`)

// GraphQL (more elegant)
query {
  article(id: "1") {
    data {
      attributes {
        title
        category {
          data {
            attributes {
              name
            }
          }
        }
      }
    }
  }
}

Preview Mode Issues

Problem: Draft content preview not working.

Solution (Next.js example):

// pages/api/preview.js
export default async function handler(req, res) {
  const { slug, secret } = req.query;

  // Check secret
  if (secret !== process.env.PREVIEW_SECRET) {
    return res.status(401).json({ message: 'Invalid token' });
  }

  // Fetch draft content from Strapi
  const article = await fetch(
    `${process.env.STRAPI_URL}/api/articles?filters[slug][$eq]=${slug}&publicationState=preview`,
    {
      headers: {
        Authorization: `Bearer ${process.env.STRAPI_API_TOKEN}`,
      },
    }
  ).then(r => r.json());

  if (!article.data[0]) {
    return res.status(404).json({ message: 'Article not found' });
  }

  // Enable Preview Mode
  res.setPreviewData({});
  res.redirect(`/articles/${slug}`);
}

Authentication State

Problem: User authentication state not synced between Strapi and frontend.

Solution:

// lib/auth.js
export const checkAuth = async () => {
  const jwt = localStorage.getItem('jwt');

  if (!jwt) return null;

  try {
    const response = await fetch(`${STRAPI_URL}/api/users/me`, {
      headers: {
        Authorization: `Bearer ${jwt}`,
      },
    });

    if (!response.ok) {
      localStorage.removeItem('jwt');
      return null;
    }

    return await response.json();
  } catch (error) {
    console.error('Auth check failed:', error);
    return null;
  }
};

Debugging Tools

Browser Developer Tools

Chrome DevTools (F12):

  • Console: Check for JavaScript errors
  • Network: Monitor API requests to Strapi
    • Filter by your Strapi URL
    • Check response times
    • Verify response data structure
  • Application: Check localStorage, cookies, session data
  • Performance: Record page load to identify bottlenecks

Strapi-Specific Debugging

Enable Strapi Debug Mode:

# .env
NODE_ENV=development
STRAPI_LOG_LEVEL=debug

Monitor Strapi Logs:

# Watch Strapi console output
npm run develop

Strapi API Testing:

  • Use Postman or Insomnia
  • Test API endpoints directly
  • Verify populate parameters
  • Check authentication headers

Analytics Debugging Tools

Browser Extensions:

Platform Tools:

  • GA4 DebugView
  • Meta Events Manager Test Events
  • GTM Preview Mode

Performance Testing Tools

Framework-Specific Debugging

Next.js

// Enable React DevTools profiler
// next.config.js
module.exports = {
  reactStrictMode: true,
  compiler: {
    removeConsole: process.env.NODE_ENV === 'production',
  },
};

// Debug API routes
// pages/api/strapi/[...slug].js
export default async function handler(req, res) {
  console.log('Strapi API Request:', req.query);
  // Proxy to Strapi
}

Gatsby

# Gatsby build with verbose output
gatsby build --verbose

# Clear cache if issues
gatsby clean && gatsby develop

Nuxt

// nuxt.config.js
export default {
  build: {
    analyze: true, // Analyze bundle size
  },
  debug: process.env.NODE_ENV === 'development',
};

Common Error Messages

"Cannot read property 'attributes' of undefined"

Cause: Strapi API response structure not handled properly.

Solution:

// Bad
const title = article.attributes.title;

// Good - with optional chaining
const title = article?.attributes?.title || 'Default Title';

// Better - with type checking
if (article?.data?.attributes) {
  const title = article.data.attributes.title;
}

"window is not defined"

Cause: Client-side code running on server.

Solution:

// Check for window
if (typeof window !== 'undefined') {
  // Client-side code
  window.gtag('event', 'page_view');
}

// Or use framework hooks
useEffect(() => {
  // Runs only on client
}, []);

"Hydration failed"

Cause: SSR HTML doesn't match client-side render.

Solution:

// Use dynamic import for client-only components
const ClientOnlyComponent = dynamic(() => import('./ClientOnly'), {
  ssr: false,
});

// Or use suppressHydrationWarning
<div suppressHydrationWarning>
  {typeof window !== 'undefined' && <ClientComponent />}
</div>

Getting Help

Strapi Support Channels

Strapi Documentation:

Strapi Discord:

GitHub Issues:

Frontend Framework Support

Next.js:

Gatsby:

Nuxt:

When to Hire a Developer

Consider hiring a developer when:

  • Complex custom functionality needed
  • Multiple persistent errors you can't resolve
  • Performance issues despite optimizations
  • Large-scale migration to Strapi
  • Custom Strapi plugin development needed
  • Advanced SSR/SSG implementations required

Find Developers:

Next Steps

Performance Issues:

Tracking Issues:

Prevention:

  • Document your setup
  • Use TypeScript for type safety
  • Implement error boundaries
  • Set up monitoring (Sentry, LogRocket, etc.)
  • Test across different rendering methods
  • Keep Strapi and frameworks updated