Broadcast Hijack
Broadcast Hijack is a FiveM Lua resource for hijacking a live Weazel-style news feed, letting one player run the broadcast while the rest of the server tunes in through a full-screen spectator overlay. It combines a physical camera-and-van setup flow, a live viewer overlay with chat, reactions, polls, and donations, and an optional post-broadcast revenue-ledger heist that branches into task-driven interiors and extraction minigames.
Features
Section titled “Features”- Hijack-Driven Broadcast Start: Retrieve a camera from an approved van, place the rig, attach the NHD, and take over the feed.
- Viewer Tune-In Overlay: Players can tune in with commands or a hotkey and watch through the live spectator camera.
- Live Audience Layer: Overlay supports chat, emotes, viewer count, polls, adverts, moderation, and SuperYap donations.
- Static/Handheld Camera Modes: Broadcaster can switch between handheld live mode and tripod static shots during the session.
- Revenue Ledger Heist: The broadcaster can convert the active session into a
kf-tasksheist route with workstation tracing, rack hacking, extraction stalls, and follow-up cash pickup stages. - Framework/Inventory Adapters: Supports Ox, QBCore, QBox, and ESX framework modes, plus multiple inventory adapters.
Perfect For
Section titled “Perfect For”- News hijack scenes where a criminal crew takes over a live feed and the whole server watches it unfold.
- Event servers that want a broadcast layer with audience interaction, donations, and on-screen polls.
- Crime escalation loops where a successful broadcast can turn into a second-stage payout heist.
Getting Started
Section titled “Getting Started”-
Download the latest version from Cfx.re Portal
Section titled “Download the latest version from Cfx.re Portal” -
Download Dependencies
Section titled “Download Dependencies”Recommended stack:
- ox_lib: must be version
v3.30.0or higher. - ox_target: the current target integration in this resource expects
ox_target. - ox_inventory: recommended inventory provider for the setup below.
kf-tasks: required for the built-in revenue-ledger heist flow.
Supported inventory adapters in
kf-broadcast:ox_inventorycodem-inventoryqs-inventoryqs-inventory-proorigen_inventorytgiann-inventory
- ox_lib: must be version
-
Install
Section titled “Install”Move the folders
kf-broadcast,kf-broadcast-assets, and the dependencies above into your server’sresourcesdirectory. -
Add to
Section titled “Add to server.cfg”server.cfgserver.cfg ensure ox_libensure ox_targetensure ox_inventoryensure kf-tasksensure kf-broadcast-assetsensure kf-broadcast -
Configure broadcaster access
Section titled “Configure broadcaster access”By default,
Config.broadcast.startAceisfalseandConfig.broadcast.allowedGroupsis empty, so any player who passes the gameplay requirements can start a broadcast. If you want to lock it down, set an ACE permission and/or allowed framework groups inconfig.lua.Optional ACE example:
server.cfg add_ace group.media kf.broadcast.start allow -
Add the recommended
Section titled “Add the recommended ox_inventory items”ox_inventoryitemsAdd the broadcast items to your ox_inventory items config. Default location:
resources/[ox]/ox_inventory/data/items.luaThe example below is for
ox_inventory. If you use another supported inventory, keep the same item names and adapt the item registration to that inventory’s format.items.lua ['kf_weazel_camera'] = {label = 'Weazel Camera',weight = 3000,stack = false,close = true,client = {export = 'kf-broadcast.deployCamera'}},['kf_weazel_nhd'] = {label = 'Network Hijack Device',weight = 500,stack = false,close = true,},['kf_weazel_revenue_ledger'] = {label = 'Copied Revenue Ledger',weight = 100,stack = false,close = true,}, -
Add the images to the inventory images folder
Section titled “Add the images to the inventory images folder”Add all the images files from
kf-broadcast/inventory-images/ingameORkf-broadcast/inventory-images/stylizedinto the ox_inventory images folder. Default location:resources/[ox]/ox_inventory/web/images -
Supply the broadcast hack device item through your own gameplay
Section titled “Supply the broadcast hack device item through your own gameplay”Add the Network Hack Device (NHD) inventory item
kf_weazel_nhdto your item dispenser method; you decide how players obtain the NHD in your server economy. Note: NHD can be disabled in the configConfig.broadcast.hijack.requireNhd.
Asset Resource
Section titled “Asset Resource”kf-broadcast-assets is required alongside kf-broadcast.
It does two jobs:
- Streams the custom broadcast props used by the hijack flow: the camera, tripod, and NHD.
- Streams a replacement YMAP that modifies the vehicle generator at the Weazel News HQ parking lot so a
rumpovan can spawn there for the recommended setup.
This is separate from Config.broadcast.managedVans. The asset resource handles the streamed map/content side; the managed-van system is an optional server-side respawned van system in config.lua.
Commands
Section titled “Commands”/tunein: viewer command to tune into the active broadcast./tuneout: viewer command to leave the active broadcast./broadcaststop: stops the active broadcast if the player has broadcast-start permission./broadcastpoll question | option 1 | option 2 | [option 3] | [option 4]: starts an audience poll during a live broadcast./broadcastpollstop: ends the active poll early.
By default, the viewer hotkey is also configured to J through Config.commands.tuneInKey.
Configuration
Section titled “Configuration”The main configuration is located in config.lua.
Config = { debug = false, notifications = true, notify = 'ox_lib', -- 'ox_lib' | 'esx_notify' | 'qb-core' | 'qbx_core' | 'okokNotify' | 'wasabi_notify', framework = 'auto', -- 'auto' | 'ox' | 'qbcore' | 'qbox' | 'esx' target = 'ox_target', inventory = 'auto', -- 'auto' | 'ox_inventory' | 'qs-inventory' | 'qs-inventory-pro' | 'codem-inventory' | 'origen_inventory' | 'tgiann-inventory' commands = { stop = 'broadcaststop', tuneIn = 'tunein', tuneOut = 'tuneout', poll = 'broadcastpoll', pollStop = 'broadcastpollstop', tuneInKey = { raw = 74, -- Virtual-key code, default J label = 'J', }, }, debugBlockTuneInOverlay = false, tuneInPrepareTimeoutMs = 10000, spectator = { liveHandheldUseTeleportFollow = false, -- false = attach with teleport fallback, true = teleport only }, headlineBannerEnabled = true, headlineBannerDurationMs = 30000, adverts = { enabled = true, movies = { 'WZL_Lifeinvader', 'WZL_Surano', 'WZL_Grand_Senora', 'WZL_BISON', 'WZL_EPSILON', 'WZL_Ammunation', 'WZL_Up_And_Atom', }, tuneIn = { enabled = true, oncePerBroadcast = true, displayDurationMs = 4000, randomStartPercentMin = 0, randomStartPercentMax = 80, }, randomDuringBroadcast = { enabled = false, minDelaySec = 120, maxDelaySec = 300, requireViewer = true, }, }, overlay = { scanlineEnabled = true, scanlineOpacity = 0.4, -- 0.0 to 1.0 tunePanelPosition = 'bottom-right', -- none | top-left | top-right | bottom-left | bottom-right bootstrapChatMessageLimit = 10, snapshotLatentBps = 50000, }, hypeMeter = { enabled = true, triggerThreshold = 100, maxHype = 150, decayIntervalSec = 5, decayAmount = 10, triggerCooldownSec = 45, viewerJoinPoints = 20, chatMessagePoints = 10, emotePoints = 4, realSuperYapPoints = 45, }, startAce = false, -- kf.broadcast.start | false allowedGroups = { --'admin', }, headlineText = 'BREAKING NEWS: WEAZEL NEWS BROADCAST INTERCEPTED', batteryDurationSec = 3600, chatHistoryLimit = 50, chatMaxLength = 120, chatCooldownMs = 1500, emoteCooldownMs = 250, emoteBatch = { enabled = true, intervalMs = 100, maxBatchSize = 32, }, moderation = { enabled = true, ace = false, -- kf.broadcast.moderate | false allowedGroups = { 'admin', }, timeoutPresetsSec = { 60, 300, 900, }, defaultTimeoutSec = 300, }, hijack = { debugDrawCaptureSphere = false, interactionRadius = 2.5, requireVanLink = true, vanLinkRadius = 250.0, vanLinkGraceSec = 60, vanLinkWarningCooldownSec = 2, tripodInteractRadius = 2.5, tripodPlacementDistance = 10.0, cameraItem = 'kf_weazel_camera', nhdItem = 'kf_weazel_nhd', showCameraRetrieveTarget = true, grantNhdOnCameraRetrieve = false, requireNhd = true, allowedVans = { { model = 'rumpo', liveries = { 0, }, }, }, blip = { enabled = true, sprite = 184, colour = 5, scale = 0.85, shortRange = true, name = 'Broadcast Camera', }, props = { cameraModel = 'prop_kf_broadcast_cam', nhdModel = 'prop_kf_broadcast_nhd', tripodModel = 'prop_kf_broadcast_tri', handBone = 28422, handCameraOffset = vector3(0.0, 0.0, 0.0), handCameraRotation = vector3(1.0, 0.0, 0.0), cameraHold = { dict = 'oddjobs@bailbond_mountain', clip = 'Idle_Camman', blendIn = 8.0, blendOut = 8.0, duration = -1, playbackRate = 1.0, lockX = false, lockY = false, lockZ = false, reapplyIntervalMs = 500, }, nhdOffset = vector3(-0.261731, 0.036752, 0.087659), nhdRotation = vector3(180.0, 0.0, 0.0), tripodCameraOffset = vector3(0.0, 0.0, 1.29), tripodCameraRotation = vector3(0.0, 0.0, 0.0), captureOffset = vector3(0.35, 0, 0.0), captureFov = 50.0, }, }, managedVans = { enabled = false, model = 'rumpo', livery = 0, respawnDelaySec = 60, healthCheckIntervalMin = 30, spawns = { vector4(-543.7345, -888.2435, 25.1393, 187.3024), vector4(-537.0546, -905.4167, 23.8630, 241.8772), vector4(-539.3694, -909.0856, 23.8616, 238.7722), vector4(-541.2062, -912.5158, 23.8616, 237.1201), vector4(-556.7697, -937.6596, 23.8513, 93.5193), vector4(-557.1396, -929.4688, 23.8594, 91.1856), vector4(-556.9586, -924.8768, 23.8674, 93.2972), vector4(-274.3217, -764.9600, 48.4239, 252.0183), vector4(-302.4780, -742.4742, 43.6053, 339.3744), vector4(938.6218, -48.4252, 78.7640, 237.6821), vector4(737.0957, 1296.9409, 360.2958, 8.8485), vector4(193.7172, 6381.9854, 31.3943, 121.4929), }, dish = { model = 'prop_satdish_s_02', attachDistance = 100.0, refreshIntervalMs = 1000, forwardOffset = -1.2, rightOffset = 0.0, heightPadding = -0.1, rotation = vector3(0.0, 0.0, 180.0), }, }, heist = { enabled = true, deathHandling = 'interior_fail_task', -- 'none' | 'interior_fail_task' | 'any_fail_task' computerBootDurationSec = 15, rackHackCooldownSec = 10, extractionPenaltySec = 30, extractionChallengeIntervalMinSec = 35, extractionChallengeIntervalMaxSec = 60, extractionChallengeResponseWindowSec = 30, extractionMinigames = { pool = { 'timing_lock', 'command_chain', 'packet_match', }, timingLock = { prompt = 'STALL DETECTED. STABILIZE TRANSFER PULSE.', zoneSizeMinPercent = 12, zoneSizeMaxPercent = 18, zoneStartMinPercent = 12, zoneStartMaxPercent = 82, cycleMsMin = 1400, cycleMsMax = 1900, roundsRequiredMin = 2, roundsRequiredMax = 3, maxStrikes = 2, }, commandChain = { prompt = 'STALL DETECTED. EXECUTE THE RECOVERY COMMAND CHAIN.', inputPool = { 'W', 'A', 'S', 'D', 'Q', 'E', }, sequenceLength = 5, stepWindowMsMin = 2500, stepWindowMsMax = 4500, maxMistakes = 2, }, packetMatch = { prompt = 'CACHE DESYNC. REBUILD THE PACKET ORDER.', valuePool = { 'A7', '4C', 'D1', '9F', 'EE', 'B2', '6A', 'C8', '31', 'F4', '8D', '72', }, sequenceLength = 4, optionCount = 8, revealDurationMs = 5000, }, }, serverRoom = { hqEntryCoords = vector3(-536.10, -886.20, 25.60), exteriorExitCoords = vector4(-537.1286, -886.4703, 25.2101, 180.0), interiorEntrance = vector4(2154.8240, 2921.0779, -81.0755, 260.2079), interiorExit = vector3(2156.40, 2922.18, -80.60), rackRouteRevealDistance = 15.0, revenueLedger = { item = 'kf_weazel_revenue_ledger', model = 'ch_prop_ch_usb_drive01x', }, workstations = { { label = 'News Desk A', coords = vector3(2166.60, 2925.50, -81.21), targetSize = vector3(1.2, 0.9, 1.8), }, { label = 'News Desk B', coords = vector3(2173.74, 2928.78, -81.22), targetSize = vector3(1.2, 0.9, 1.8), }, { label = 'News Desk C', coords = vector3(2180.17, 2924.32, -81.22), targetSize = vector3(1.2, 0.9, 1.8), }, { label = 'News Desk D', coords = vector3(2179.49, 2916.60, -81.22), targetSize = vector3(1.2, 0.9, 1.8), }, { label = 'News Desk E', coords = vector3(2172.36, 2913.29, -81.22), targetSize = vector3(1.2, 0.9, 1.8), }, }, racks = { { label = 'Rack A1', coords = vector3(2170.64, 2934.42, -84.20), }, { label = 'Rack A3', coords = vector3(2193.31, 2938.45, -84.19), }, { label = 'Rack A9', coords = vector3(2222.08, 2942.52, -84.20), }, { label = 'Rack B2', coords = vector3(2169.80, 2908.54, -84.20), }, { label = 'Rack B8', coords = vector3(2206.57, 2900.97, -84.20), }, { label = 'Rack C1', coords = vector3(2166.64, 2907.60, -84.20), }, { label = 'Rack C3', coords = vector3(2154.34, 2906.52, -84.20), }, { label = 'Rack D2', coords = vector3(2166.36, 2933.35, -84.19), }, { label = 'Rack D8', coords = vector3(2130.74, 2940.81, -84.21), }, { label = 'Rack D15', coords = vector3(2114.37, 2943.68, -84.21), }, }, }, extractionDurationTiers = { { minAmount = 100000, durationSec = 300, }, { minAmount = 50000, durationSec = 240, }, { minAmount = 1, durationSec = 180, }, }, forgery = { exchangeDurationMs = 3000, interiorEntrance = vector4(1173.7865, -3196.5505, -39.0080, 89.5980), laptopCoords = vector3(1159.46, -3192.41, -38.52), npc = { coords = vector4(1159.4460, -3192.3931, -39.0080, 284.1677), models = { 'cs_carbuyer', 'g_m_m_chiboss_01', 'a_m_y_business_02', 'csb_money', }, }, exteriorLocations = { { label = 'Forgery Site 1', coords = vector4(1240.1384, -3239.0088, 6.0288, 103.9778) }, { label = 'Forgery Site 2', coords = vector4(646.6183, -3017.9878, 7.3362, 100.5362) }, { label = 'Forgery Site 3', coords = vector4(-318.2638, -2718.1672, 7.5482, 46.3471) }, { label = 'Forgery Site 4', coords = vector4(1125.2495, -1010.4940, 44.6702, 279.6118) }, { label = 'Forgery Site 5', coords = vector4(916.4738, 3576.9683, 33.5560, 96.7104) }, { label = 'Forgery Site 6', coords = vector4(1961.0105, 5184.9502, 47.9398, 94.8243) }, { label = 'Forgery Site 7', coords = vector4(-58.1230, 6441.5439, 32.6857, 225.6540) }, { label = 'Forgery Site 8', coords = vector4(-3179.1436, 1093.3934, 20.8407, 246.8654) }, { label = 'Forgery Site 9', coords = vector4(-1100.3795, 2722.2498, 18.8004, 223.1808) }, { label = 'Forgery Site 10', coords = vector4(172.3683, 2801.6531, 45.6606, 188.6549) }, }, }, money = { pickupCoords = vector3(1123.3427, -3198.6250, -40.49136), targetSize = vector3(0.45, 0.25, 0.3), targetRotation = 0.0, npc = { coords = vector4(1121.8569, -3197.3987, -40.3949, 263.0054), models = { 'cs_josh', 'g_m_y_korlieut_01', }, }, stagedBag = { model = 'prop_cs_heist_bag_02', coords = vector4(1123.3427, -3198.6250, -40.49136, 357.0542), }, interiorEntrances = { entrance1 = vector4(1138.1208, -3199.1963, -39.6657, 13.0977), entrance2 = vector4(1118.7831, -3193.3276, -40.3915, 186.0793), }, exteriorLocations = { { label = 'Cash Site 1', coords = vector4(1239.3817, -3168.1074, 7.1049, 93.3469), entranceKey = 'entrance2' }, { label = 'Cash Site 2', coords = vector4(448.6443, -2761.4460, 7.1009, 248.3218), entranceKey = 'entrance1' }, { label = 'Cash Site 3', coords = vector4(257.4132, -3062.6667, 5.8630, 225.6768), entranceKey = 'entrance1' }, { label = 'Cash Site 4', coords = vector4(-1150.4110, -1567.8495, 4.4282, 214.0638), entranceKey = 'entrance1' }, { label = 'Cash Site 5', coords = vector4(323.0804, 364.0758, 105.3210, 176.7077), entranceKey = 'entrance2' }, { label = 'Cash Site 6', coords = vector4(619.0322, 2784.5139, 43.4812, 185.1299), entranceKey = 'entrance2' }, { label = 'Cash Site 7', coords = vector4(183.8829, 6373.5435, 32.3440, 36.9033), entranceKey = 'entrance2' }, { label = 'Cash Site 8', coords = vector4(325.5690, -994.5185, 29.3124, 0.9140), entranceKey = 'entrance1' }, { label = 'Cash Site 9', coords = vector4(-50.2415, 1911.1753, 195.7054, 278.1860), entranceKey = 'entrance1' }, { label = 'Cash Site 10', coords = vector4(-512.0488, -1747.3262, 19.2469, 59.4107), entranceKey = 'entrance1' }, }, }, bag = { model = 'prop_cs_heist_bag_02', payoutItem = 'money', countChunkAmount = 5000, damagePenaltyAmount = 1000, cashoutDurationMs = 2500, }, dispatch = { enabled = false, provider = 'auto', -- auto | ps-dispatch | qb-dispatch | ls-dispatch | cd_dispatch resources = { psDispatch = 'ps-dispatch', qbDispatch = 'qb-dispatch', lsDispatch = 'ls-dispatch', cdDispatch = 'cd_dispatch', }, title = 'Server Farm Intrusion', message = 'Unauthorized entry detected at the Weazel News server farm.', code = '10-90', codeName = 'suspiciousactivity', priority = 2, recipientJobs = { 'police', }, psJobs = { 'leo', }, blip = { sprite = 161, colour = 1, scale = 1.2, length = 3, radius = 0, flash = true, sound = 1, }, }, }, minigame = { enabled = false, provider = 'ox_lib', }, superYap = { enabled = true, paymentSource = 'bank', -- bank | inventory moneyItem = 'money', permanentBadgeThreshold = 1000000, presetAmounts = { 1000, 5000, 15000, 50000, 100000, 250000, }, -- `max` is optional and auto-derived from the next tier's `min` when omitted. tiers = { [1] = { min = 5000, durationSec = 30, maxChars = 60, }, [2] = { min = 15000, durationSec = 60, maxChars = 60, }, [3] = { min = 50000, durationSec = 120, maxChars = 80, }, [4] = { min = 100000, durationSec = 300, maxChars = 120, }, [5] = { min = 250000, durationSec = 600, maxChars = 120, }, }, }, poll = { enabled = true, durationSec = 240, resultDurationSec = 30, questionMaxLength = 120, optionMaxLength = 40, minOptions = 2, maxOptions = 4, voteCooldownMs = 400, },}