JG Docs
Used Vehicles

Cloudflare R2

Cloudflare R2 provides S3-compatible object storage. JG Used Vehicles creates a temporary R2 upload URL, then the in-game browser uploads each photo directly to R2.

You need:

  • An R2 bucket.
  • An R2 access key ID and secret access key.
  • Your Cloudflare account ID.
  • A public URL for reading uploaded photos.
  • CORS enabled for browser PUT uploads.

Create an R2 bucket

  1. Open the Cloudflare dashboard.
  2. Open R2 Object Storage.
  3. Create a bucket, for example used-vehicles.
  4. Save the bucket name.

Create an R2 API token

  1. Open R2 Object Storage in the Cloudflare dashboard.
  2. Open Manage R2 API Tokens.
  3. Create an API token with object read and write access for the bucket.
  4. Copy the access key ID and secret access key.

Cloudflare documents this at R2 API tokens.

Make the bucket public

Vehicle photos must be reachable by players and by the server after upload. Connect either an R2 public development URL or a custom domain to the bucket.

Cloudflare documents both options at Public buckets.

Enable CORS for direct uploads

The in-game browser uploads directly to R2, so the bucket must allow browser PUT requests from jg-usedvehicles.

Use this as a starting point:

[
  {
    "AllowedOrigins": ["https://cfx-nui-jg-usedvehicles"],
    "AllowedMethods": ["PUT"],
    "AllowedHeaders": ["*"],
    "ExposeHeaders": ["ETag"],
    "MaxAgeSeconds": 3000
  }
]

If you renamed the resource, replace jg-usedvehicles in AllowedOrigins.

Configure JG Used Vehicles

Set the provider in config/config.lua:

config/config.lua
Config.ImageStorageProvider = "r2"

Add the R2 settings in config/config.photos.lua:

config/config.photos.lua
Config.ImageStorageProviders.r2 = {
  accountId = "YOUR_CLOUDFLARE_ACCOUNT_ID",
  bucket = "used-vehicles",
  accessKeyId = "YOUR_R2_ACCESS_KEY_ID",
  secretAccessKey = "YOUR_R2_SECRET_ACCESS_KEY",
  endpoint = "",
  publicUrl = "https://pub-xxxxxxxxxxxxxxxx.r2.dev",
  prefix = "used-vehicles",
  region = "auto",
  forcePathStyle = true,
}

Use your custom domain in publicUrl if you configured one:

config/config.photos.lua
publicUrl = "https://images.example.com"

Do not include a trailing slash in publicUrl.

Test the final URL

Restart jg-usedvehicles and open the vehicle camera. Take one photo after the provider check passes, then confirm the photo appears in the photo library.

If the photo uploads but does not display, copy its URL and open it in a browser. Check the bucket's public access or custom domain configuration if the URL does not load.

Config fields

FieldRequiredDescription
accountIdYesCloudflare account ID.
bucketYesR2 bucket name.
accessKeyIdYesR2 access key ID.
secretAccessKeyYesR2 secret access key.
endpointNoOptional custom S3 API endpoint. Leave empty for standard R2.
publicUrlYesPublic URL used to load uploaded photos.
prefixNoFolder-style prefix. Defaults to "used-vehicles" in the example config.
regionNoR2 uses "auto".
forcePathStyleNoKeep this enabled for R2.

Troubleshooting

Last updated 26 August 2026

On this page