Menu
Products
Products
Video Hosting
Upload and manage your videos in a centralized video library.
Image Hosting
Upload and manage all your images in a centralized library.
Galleries
Choose from 100+templates to showcase your media in style.
Video Messaging
Record, and send personalized video messages.
CincoTube
Create your own community video hub your team, students or fans.
Pages
Create dedicated webpages to share your videos and images.
Live
Create dedicated webpages to share your videos and images.
For Developers
Video API
Build a unique video experience.
DeepUploader
Collect and store user content from anywhere with our file uploader.
Solutions
Solutions
Enterprise
Supercharge your business with secure, internal communication.
Townhall
Webinars
Team Collaboration
Learning & Development
Creative Professionals
Get creative with a built in-suite of editing and marketing tools.
eCommerce
Boost sales with interactive video and easy-embedding.
Townhall
Webinars
Team Collaboration
Learning & Development
eLearning & Training
Host and share course materials in a centralized portal.
Sales & Marketing
Attract, engage and convert with interactive tools and analytics.
"Cincopa helped my Enterprise organization collaborate better through video."
Book a Demo
Resources
Resources
Blog
Learn about the latest industry trends, tips & tricks.
Help Centre
Get access to help articles FAQs, and all things Cincopa.
Partners
Check out our valued list of partners.
Product Updates
Stay up-to-date with our latest greatest features.
Ebooks, Guides & More
Customer Stories
Hear how we've helped businesses succeed.
Boost Campaign Performance Through Video
Discover how to boost your next campaign by using video.
Download Now
Pricing
Watch a Demo
Demo
Login
Start Free Trial
When building an application with Strapi, you may need to deliver private video content that is accessible only to specific users, such as subscribers or members. Simply hiding video links on the frontend is not secure; users could still access videos if file URLs are public. To ensure proper protection, Strapi provides role-based permissions, custom policies, and storage security mechanisms to keep your videos safe. Prerequisites Node.js v18.x (recommended for Strapi v4) npm or Yarn (package manager) Basic Understanding of Strapi CLI Set Up a Strapi Project using this guide: Getting Started with Strapi: A Beginner’s Guide Install and Configure Video Field Plugin To enable video embedding, install the video field plugin. Install the Plugin : With npm : npm install @sklinet/strapi-plugin-video-field With yarn : yarn add @sklinet/strapi-plugin-video-field Enable the plugin in config/plugins.js : module.exports = () => ({ 'video-field': { enabled: true } }); Run build : npm run build OR yarn build Once installed, you’ll see Video Field in the Content-Type Builder. A sample stored value looks like this: { 'provider': 'youtube', 'providerUid': 'RANDOMUID', 'url': 'https://www.youtube.com/watch?v=RANDOMUID' } Secure Embedded Video Sources If you plan to embed videos from providers such as YouTube or Vimeo, extend the Content Security Policy (CSP) in config/middlewares.js : module.exports = [ 'strapi::errors', { name: 'strapi::security', config: { contentSecurityPolicy: { useDefaults: true, directives: { 'frame-src': [ ''self'', 'youtube.com', 'www.youtube.com', 'vimeo.com', '*.vimeo.com', 'facebook.com', 'www.facebook.com' ], 'media-src': [''self'', 'data:', 'blob:'], }, }, }, }, 'strapi::cors', 'strapi::poweredBy', 'strapi::logger', 'strapi::query', 'strapi::body', 'strapi::session', 'strapi::favicon', 'strapi::public', ]; This ensures that only trusted video providers can be embedded in your application. Configure User Roles and Permissions Strapi v4 has two types of roles: Admin Roles : Control access to the Strapi admin panel. Users & Permissions Plugin Roles : Control access for application users (public, authenticated, custom roles). For private video content, use the Users & Permissions Plugin Roles. Steps to Configure : Step 1 : In the Strapi admin panel, go to Settings > Users & Permissions Plugin > Roles . Step 2 : Create a custom role (e.g., Subscriber ). Step 3 : Assign permissions for your video content types ( Find , FindOne , Create , Update , Delete ). Step 4 : Save changes. Step 5 : Assign this role to front-end users either via registration flow or manually in the “ Users ” section. Implement Custom Logic for Granular Access Basic role permissions may not be enough. For example, you may want users to access only the videos they own. Policies let you enforce such rules. Example Policy : src/policies/isOwner.js module.exports = async (ctx, config, { strapi }) => { const { user } = ctx.state; // authenticated user const { id } = ctx.params; // video ID from URL // Replace 'video' with the name of your content-type const video = await strapi.db.query('api::video.video').findOne({ where: { id }, }); if (!video || video.owner !== user.id) { return false; // Access denied } return true; // Access granted }; Apply the policy in your routes file (src/api/video/routes/video.js) : module.exports = { routes: [ { method: 'GET', path: '/videos/:id', handler: 'video.findOne', config: { policies: ['isOwner'], }, }, ], }; This ensures that only the owner of a video can retrieve it. Note: In the query above, api::video.video refers to a collection type called “video.” Update this identifier to match your actual content type name. Securing Video Storage Permissions and policies protect the API layer, but securing where the actual video files are stored is equally important. If using Local Uploads, files stored in Strapi’s /public/uploads folder are publicly accessible if requested directly. Instead, move sensitive video files outside the /public directory and serve them through a secured Strapi route with authentication checks. If using Cloud Storage (e.g., AWS S3), store files as private in the bucket. Generate signed URLs for users to access files temporarily after authentication. Example : AWS S3 Signed URL Service // src/services/s3.js const AWS = require('aws-sdk'); const s3 = new AWS.S3({ accessKeyId: process.env.AWS_ACCESS_KEY, secretAccessKey: process.env.AWS_SECRET_KEY, region: process.env.AWS_REGION, }); module.exports = { getSignedUrl(key) { return s3.getSignedUrl('getObject', { Bucket: process.env.AWS_BUCKET, Key: key, Expires: 60, // expires in 60 seconds }); }, }; Example Controller that uses the signed URL : // src/api/video/controllers/video.js const s3Service = require('../../../services/s3'); module.exports = { async getSecureUrl(ctx) { const { id } = ctx.params; const { user } = ctx.state; const video = await strapi.db.query('api::video.video').findOne({ where: { id } }); if (!video || video.owner !== user.id) { return ctx.forbidden('You do not have access to this video.'); } const url = s3Service.getSignedUrl(video.fileKey); return { url }; } }; This ensures that even if someone shares a raw S3 file link, it won’t work, since only signed (expiring) URLs are served to authenticated users.