FiveM screenshot-basic: Sending Screenshots to Discord

If you run a FiveM roleplay server, being able to capture what a player sees at any moment is one of the most practical moderation tools available. Whether you are catching modders mid-exploit, documenting a report, or auto-logging suspicious behaviour, screenshot-basic is the go-to developer resource for the job. This guide walks through a complete installation, shows you how to pipe screenshots straight into a Discord channel via webhook, explains the server-side API for anti-cheat scripts, and covers the most common pitfalls.

What screenshot-basic Actually Is

screenshot-basic is an official Cfx.re resource maintained under the citizenfx GitHub organisation. It uses the same WebGL/OpenGL ES render-target calls that power the game view plugin, wrapping them with Three.js to copy the frame buffer asynchronously through NUI. The result is a base64 data URI (or a server-saved file) of exactly what the player sees on their screen at that instant.

One important caveat before you dive in: screenshot-basic exposes no end-user commands on its own. It is a developer API only — a library that other resources call through exports. You will need either a companion resource (such as discord-screenshot by jaimeadf) or your own Lua/JS code to trigger screenshots and deliver them somewhere useful.

Step 1 — Install screenshot-basic

Clone the repository directly into your resources folder. The convention is to put community or local resources inside a named sub-folder so they do not clash with cfx-server-data assets.

cd /path/to/server/resources/[local]
git clone https://github.com/citizenfx/screenshot-basic.git screenshot-basic

Then add it to your server.cfg so it starts before any resource that depends on it:

ensure screenshot-basic

No build step is required when cloning from master — the compiled output in dist/ is committed to the repository. If you ever modify the TypeScript source, you will need Node.js, Yarn, and Webpack to rebuild.

Step 2 — Understand the Three Exports

screenshot-basic exposes three exports. Knowing which one to use for which job saves a lot of trial and error.

ExportSideReturnsBest for
requestScreenshotClientBase64 data URI via callbackIn-game display, bug reports triggered by the player
requestScreenshotUploadClientRemote server response via callbackUploading directly to Discord webhook or any HTTP endpoint
requestClientScreenshotServerData URI or saved file via callbackAdmin/anti-cheat triggered capture (player cannot cancel)

Step 3 — Send a Screenshot to Discord (Client-Side Upload)

The simplest Discord integration calls requestScreenshotUpload from a client script and posts the image directly to a Discord webhook URL. Discord expects the file to be uploaded as a multipart/form-data POST with the field name files[].

First, create a webhook in your Discord server: Server Settings → Integrations → Webhooks → New Webhook. Copy the webhook URL.

Then in your client-side Lua resource:

-- client.lua
RegisterCommand('screenshot', function()
  exports['screenshot-basic']:requestScreenshotUpload(
    'https://discord.com/api/webhooks/YOUR_WEBHOOK_ID/YOUR_WEBHOOK_TOKEN',
    'files[]',
    { encoding = 'jpg', quality = 0.85 },
    function(data)
      -- data contains Discord's JSON response
      print('[screenshot-basic] Upload complete: ' .. tostring(data))
    end
  )
end, false)

A few things to note here. The field name files[] is Discord’s expected multipart key for file attachments — do not change it. The encoding option accepts 'png', 'jpg', or 'webp'; 'jpg' is the default and produces the smallest files. Quality is a float from 0.0 to 1.0, defaulting to 0.92.

Because this is a client-side export, the screenshot runs in the player’s NUI context. That means a player running the command themselves can see it happen. For invisible, server-triggered captures, move to Step 4.

Step 4 — Server-Side Screenshots for Anti-Cheat

The requestClientScreenshot export runs on the server and silently instructs a specific client to capture their screen. This is the backbone of screenshot-based anti-cheat integrations.

Version requirement: The player’s FiveM client must be at least build 1129160, and your server must run artifact pipeline 1011 or higher. Modern FiveM servers and clients satisfy this automatically.

-- server.lua
-- Call this from any server-side event, e.g. triggered by your anti-cheat

local function capturePlayerScreen(playerId)
  exports['screenshot-basic']:requestClientScreenshot(
    playerId,
    {
      fileName = 'cache/anticheat-' .. playerId .. '-' .. os.time() .. '.jpg',
      encoding = 'jpg',
      quality  = 0.90,
    },
    function(err, data)
      if err then
        print('[AC] Screenshot error for ' .. playerId .. ': ' .. tostring(err))
        return
      end
      -- data is a file path (when fileName is set) or a data URI (when omitted)
      print('[AC] Screenshot saved: ' .. tostring(data))

      -- Forward to Discord via PerformHttpRequest or a webhook helper
      -- Replace with your own webhook forwarding logic
    end
  )
end

RegisterCommand('screencap', function(source, args)
  local target = tonumber(args[1])
  if target then capturePlayerScreen(target) end
end, true) -- true = server-only command

When fileName is provided, the image is written to that relative path on the server and the callback receives the path string. When fileName is omitted, the callback receives a base64 data URI instead. If you want to forward that data URI to Discord from the server side, you will need to convert it to binary and send it via PerformHttpRequest — or use a ready-made wrapper resource.

Using a Companion Resource: discord-screenshot

If you want a pre-built admin command with Discord delivery out of the box, the community resource discord-screenshot by jaimeadf is the most widely used option. It sits on top of screenshot-basic and handles the webhook POST, player embeds, and ACE permission gating for you.

After downloading and placing it in your resources folder, your server.cfg needs both resources:

ensure screenshot-basic
ensure discord-screenshot

Open the resource’s settings.json and set at minimum:

{
  "webhookUrl": "https://discord.com/api/webhooks/YOUR_WEBHOOK_ID/YOUR_WEBHOOK_TOKEN",
  "commandName": "screenshot",
  "commandPermission": "request.screenshot",
  "screenshotOptions": {
    "encoding": "jpg",
    "quality": 0.9
  }
}

Grant the permission to your admin ace group in server.cfg:

add_ace group.admin request.screenshot allow

Admins can then run /screenshot in-game and the result appears in your Discord channel within a couple of seconds. Keep one thing in mind: the webhook URL is transmitted as part of the resource configuration and can be visible to players who inspect resource files or NUI network calls. Treat it as a low-sensitivity webhook and rotate it if it leaks.

For a well-rounded moderation toolkit, pair this with the guides on ban and kick management and vMenu setup, which cover the broader admin workflow that screenshot logging fits into.

Troubleshooting Common Issues

Black screenshots. This is the most frequently reported problem and it is tied to the game’s display mode — it commonly shows up after the client switches between fullscreen and borderless modes of the same resolution, which can break the buffer the capture relies on. The usual fix is to have players use windowed or borderless windowed mode and avoid toggling display modes mid-session. You cannot force this server-side, but you can document it in your server rules or use a convar check.

Resource fails to load. Confirm you are running a recent FiveM server artifact. The resource depends on cfx-server-data being updated after 2019-01-15; older builds will throw manifest errors. Also check that ensure screenshot-basic appears before any resource that exports from it in your server.cfg.

Discord returns a 400 error. The most common cause is using the wrong field name. Discord requires files[] exactly — no variation. A 401 means the webhook URL has been revoked or is malformed.

If you are having broader resource-loading trouble, the FiveM resource loading errors troubleshooting guide covers the full diagnosis process. For fully managed FiveM hosting where artifact updates happen automatically, see our FiveM server hosting plans — no manual binary management required.

Full documentation for the resource is available at the FiveM docs hub, which covers setup through to advanced scripting.

Frequently Asked Questions

Can a player block or prevent a server-side screenshot?

Not easily. The requestClientScreenshot export is initiated entirely server-side and the client resource handles capture without any player-facing prompt. A player running a modified client could theoretically intercept the NUI call and return a blank or fake frame, which is why screenshot evidence should always be treated as supporting evidence rather than conclusive proof on its own.

What is the difference between requestScreenshot and requestScreenshotUpload?

requestScreenshot returns the image as a base64 data URI inside the client’s Lua environment — useful for displaying it in a NUI panel or passing it to another local system. requestScreenshotUpload does the HTTP POST itself from within the NUI layer, sending the image directly to any URL you specify (Discord, an image host, your own API). For Discord delivery, requestScreenshotUpload is the simpler path since Discord accepts raw multipart file uploads via webhook.

Does screenshot-basic work on RedM as well?

The official citizenfx/screenshot-basic manifest declares game 'common', which in principle covers both FiveM and RedM. Community forks explicitly targeting RedM exist, but the upstream resource should work as long as the rendering context is available. Test in a development environment before relying on it for production moderation on a RedM server.

Ready to play?

Run your own FiveM server with XGamingServer

Spin up an always-on FiveM server your friends can join in minutes — no port-forwarding, no tech headaches.

99.9%Uptime SLA
< 5 minInstant setup
24/7Human support
DDoSProtected
Instant setup Your server is live in minutes with a one-click control panel.
Mods & plugins Install mods, plugins and workshop content in a few clicks.
DDoS protected Enterprise DDoS mitigation keeps your server online 24/7.
Low-latency hardware Premium CPUs & NVMe SSDs for lag-free multiplayer.
Free backups Automatic backups so your world is never lost.
Real human support Gamers helping gamers — 24/7, no bots, no scripts.

Pick your FiveM plan & play in minutes

See all plans
Starter $8.40/mo 4 GB RAM Renews $12/mo Buy now
Rookie $17.50/mo 8 GB RAM Renews $25/mo Buy now
Pro $24.50/mo 12 GB RAM Renews $35/mo Buy now