FiveM Phone Scripts Troubleshooting FAQ: 12 Common Issues Fixed
Phone scripts are the most feature-rich resources on a FiveM server β messaging, calls, social media, GPS, and a dozen apps in one bundle. More features mean more failure surface. This guide covers the 12 most common phone failures on ESX, QBCore, and QBox with diagnostic steps and working code.

Phone scripts are the most feature-rich resources on a FiveM server. Messaging, calls, social media, GPS, camera, app store, dark mode β often a dozen apps in one bundle. The feature surface means more failure surface. When any single app breaks, the phone looks entirely broken to players.
This guide walks through the twelve phone script failures we see most often across qs-smartphone, npwd, lb-phone, and the QBCore/ESX defaults. Each section covers how to diagnose the root cause, the fix that resolves it in most cases, and the integration edge case that catches experienced admins.
Quick Diagnosis Table

Before diving into individual issues, match the symptom you see to the most likely root cause.
| Symptom | Most likely cause | First thing to check |
|---|---|---|
| Keybind does nothing | Resource not started / no phone item | F8 console + inventory |
| Phone opens blank | NUI build skipped | npm run build in resource folder |
| Contacts empty | Identifier mismatch | SELECT owner FROM phone_contacts |
| Messages don't send | SQL schema mismatch | Server console for SQL errors |
| Camera black screen | screenshot-basic missing | ensure screenshot-basic |
| Social feed blank | App tables missing | Re-run phone SQL install |
| App store errors | App metadata drift | Re-run phone migration SQL |
| GPS does nothing | Other script clearing waypoints | HUD/minimap scripts disabled |
| Calls don't connect | VOIP resource integration | Voice resource ensure order |
| No notification sounds | NUI audio autoplay block | F8 devtools warnings |
| Dark mode doesn't persist | localStorage cleared | Store server-side instead |
| Custom app missing | App not in manifest | Grep resource for app name |
| Billing app broken | Event name mismatch | Billing resource events |
Use this table as a triage filter. Once you've narrowed the bucket, jump to the detailed section below.
1. Phone Not Opening
When the phone keybind does nothing, start with the basics: is the resource running, is the NUI built, and does the player meet the phone's requirements?
-- Test in F8 console
start qs-smartphone -- or your phone resource name
If this fails with couldn't find resource, the resource isn't installed. If it starts but the phone still doesn't open, check F8 for NUI errors.
Fix checklist, in order:
- Resource is
ensure-ed inserver.cfgafter your framework - NUI build step completed:
cd resources/[phone]/qs-smartphone/
npm install
npm run build
- Player has a phone item in inventory (if required):
-- QBCore: qb-core/shared/items.lua
['phone'] = {
['name'] = 'phone',
['label'] = 'Phone',
['weight'] = 500,
['type'] = 'item'
},
- No NUI errors in F8 console β press F8, open DevTools, check both Console and Network panels.
Modern phone scripts (qs-smartphone, npwd, lb-phone) all use React or Vue and require a build step. Skipping npm run build is the single most common install mistake.
2. Contacts Missing
Contacts live in a database table, typically phone_contacts or phone_contacts_<framework>. Verify the table is populated:
SELECT COUNT(*) FROM phone_contacts WHERE identifier = 'YOUR_IDENTIFIER';
DESCRIBE phone_contacts;
If the table exists but contacts don't load for a specific player, the identifier format has drifted. Servers that migrated from Steam hex to license IDs or to citizen IDs need to migrate their phone_contacts owner columns:
-- Example: migrate steam: to citizenid
UPDATE phone_contacts pc
JOIN players p ON p.identifier = pc.identifier
SET pc.identifier = p.citizenid
WHERE pc.identifier LIKE 'steam:%';
Always back up the table before running migrations.
3. Messages Not Sending
Message failures are almost always SQL errors in the phone_messages insert. Three common causes:
- Column name mismatch β the script expects
sender_identifierbut the table hassenderIdentifier - Missing NOT NULL column β a recent phone update added a
read_statuscolumn that's NOT NULL with no default - Foreign key violation β the receiver phone number isn't registered, so the FK constraint rejects the insert
Test a direct insert to isolate:
INSERT INTO phone_messages (sender, receiver, message, date)
VALUES ('1001', '1002', 'Test message', NOW());
If that works, the phone script is wrong. If it fails, the schema is wrong.
Enable SQL error logging in your server config so silent failures become loud ones.
4. Camera App Crashes
The phone camera uses screenshot-basic to capture and upload images. Without it, the camera crashes on first use.
# server.cfg
ensure screenshot-basic
ensure qs-smartphone
Configure screenshot-basic with an upload destination. Most phone scripts use Imgur, some use custom upload endpoints. Check the phone's camera config:
Config.ScreenshotResource = 'screenshot-basic'
Config.ScreenshotUploader = 'imgur' -- or 'custom'
Config.ImgurClientId = 'your-client-id'
A missing Imgur client ID produces a silent failure β the screenshot captures but never uploads. Watch the server console when taking a photo.
5. Social Media Not Loading
Twitter/Instagram clones in phone scripts are self-contained apps with their own tables. If the feed loads blank:
SELECT COUNT(*) FROM phone_twitter;
SELECT * FROM phone_twitter_accounts WHERE identifier = 'YOUR_IDENTIFIER';
If the table is missing entirely, re-run the phone script's SQL install file. Most phones bundle all app tables into a single phone.sql that creates everything β running it is safe (uses CREATE TABLE IF NOT EXISTS).
If tables exist but data doesn't show, check F8 DevTools Network tab for CORS errors or failed iframe loads. Some phones load social media apps in sandboxed iframes that need explicit permission.
6. App Store Errors
App store errors come from app metadata drift. Each installable app needs a valid entry:
| Column | Required | Notes |
|---|---|---|
name | Yes | Matches app folder |
label | Yes | Display name |
icon | Yes | Path to icon file |
version | Yes | Semver string |
enabled | Yes | Boolean |
category | Varies | New in some phone versions |
min_version | Varies | New in some phone versions |
The most common cause is a phone update that added new columns without running the migration. Re-run the phone's migration SQL to align schema with the current version.
7. GPS Not Working
Phone GPS calls SetNewWaypoint(x, y) client-side. If setting a destination does nothing, verify the coordinates are valid:
-- Debug: log what the phone is sending
RegisterNUICallback('setWaypoint', function(data, cb)
print(('[phone-gps] waypoint: %s, %s'):format(tostring(data.x), tostring(data.y)))
SetNewWaypoint(data.x + 0.0, data.y + 0.0)
cb({ ok = true })
end)
If coordinates log correctly but the waypoint doesn't appear, another script is clearing it. HUD replacements and custom minimaps are the usual culprits β they call DeleteWaypoint on their own update loop. Disable them temporarily to isolate.
8. Phone Calls Dropping
Phone calls depend on your VOIP resource (pma-voice, mumble-voip). Verify the integration:
-- Phone config
Config.VoiceResource = 'pma-voice'
Config.EnableVoiceCalls = true
Fix checklist:
- Voice resource is
ensure-ed BEFORE the phone in server.cfg - Voice resource's exports match what the phone expects
- Phone version matches voice resource version (pma-voice had breaking changes in v6)
- Player's mic permissions granted in Cfx settings
If calls connect (ringing works) but audio is silent, the voice resource isn't opening a private call channel. This is usually a version mismatch β the phone is calling an export that the voice resource renamed.
9. Notification Sounds Missing
Notification sound failures have three causes:
- Files missing from resource β check the phone's
audio/orhtml/sounds/folder - Not declared in fxmanifest.lua β the
filesblock must include audio paths:
files {
'html/**/*',
'html/sounds/*.mp3',
'html/sounds/*.ogg',
}
- NUI audio autoplay blocked β modern Chromium NUI blocks audio until user interaction. Watch F8 DevTools for:
play() failed because the user didn't interact with the document first
Most phones handle this with an on-load click, but custom forks often break it.
10. Dark Mode Issues
Dark mode is a pure NUI toggle β a CSS class on the root element. If clicking the toggle does nothing:
- Check F8 DevTools Console for JavaScript errors on click
- Inspect the root element to see if the
darkclass is being added - If the class is added but nothing visually changes, the stylesheet doesn't define dark mode selectors
If dark mode toggles correctly but resets between sessions, the phone is storing the preference in localStorage β NUI localStorage gets cleared between resource restarts. Fix by storing the preference server-side:
CREATE TABLE phone_settings (
identifier VARCHAR(50) PRIMARY KEY,
dark_mode BOOLEAN DEFAULT FALSE,
notifications_enabled BOOLEAN DEFAULT TRUE
);
Load on phone open, save on toggle.
11. Custom Apps Not Appearing
Custom apps need three things, all in sync:
- Config entry β in the phone's app config, matching the folder name
- Files present β HTML/JS at the path declared in config
- Manifest inclusion β in fxmanifest.lua's
filesblock so NUI serves them
-- fxmanifest.lua must include custom app files
files {
'html/apps/my-custom-app/**/*',
}
Missing any one makes the app invisible. Grep the phone resource for your app name:
grep -r "my-custom-app" resources/[phone]/qs-smartphone/
You should see hits in config, fxmanifest.lua, and the app folder itself.
12. Billing App Not Working
Phone billing apps bridge to a separate billing/invoicing resource. The three most common: okokBilling, qb-banking, esx_billing.
-- Phone billing config
Config.BillingResource = 'okokBilling'
Config.BillingEvents = {
send = 'okokBilling:server:SendInvoice',
list = 'okokBilling:server:GetInvoices',
pay = 'okokBilling:server:PayInvoice',
}
Event names must match on both sides. If the billing resource renamed an event in a recent update, your phone stops working silently. Trace the events:
-- Phone side: log what it's emitting
RegisterNUICallback('sendInvoice', function(data, cb)
print(('[phone-billing] emit: %s'):format(Config.BillingEvents.send))
TriggerServerEvent(Config.BillingEvents.send, data)
cb({ ok = true })
end)
If the emit logs but the billing resource never receives it, check the receiving handler's registered event name for a typo or rename.
Recommended Scripts
When you need a phone script that just works β framework-native, actively maintained, documented β check the VertexMods catalog:
- FiveM Phone Scripts β Premium and free phone resources
- Best FiveM Scripts 2026 β Top-rated scripts across all categories
- FiveM Troubleshooting Guide β Broader troubleshooting playbook
- FiveM Error Codes Fixes β Decoding common error messages
Frequently Asked Questions
Why is my FiveM phone not opening when I press the keybind?
Three common causes: (1) the phone resource isn't ensure-ed in server.cfg or started after the framework, (2) the NUI build step was skipped (modern phones need npm install && npm run build inside the resource folder), or (3) the player doesn't have a phone item in inventory when the script requires one. Check F8 for NUI errors first, then verify the inventory requirement in the phone's config.
Why are contacts missing from my FiveM phone?
Missing contacts mean either the phone_contacts table is empty, or the player's identifier format doesn't match the stored records. Run SELECT COUNT(*) FROM phone_contacts WHERE identifier = ? with your actual identifier β if zero rows, contacts never wrote. If non-zero but the phone shows none, your server probably switched identifier formats (Steam hex to license to citizenid) and old records don't match new identifiers.
Why aren't messages sending on my FiveM phone script?
Message send failures are almost always SQL errors in the phone_messages insert. Check the server console for errors when hitting send. Common causes: column mismatch (the script expects sender_identifier but the table has senderIdentifier), missing NOT NULL column, or foreign key violation if the receiver isn't registered. Test by inserting directly via SQL to isolate whether it's the script or the DB.
Why does the camera app crash my FiveM phone?
The camera crashes when the screenshot-basic resource is missing, not started, or missing its upload configuration. Ensure screenshot-basic is running, and check the phone's camera config for the upload method β most phones use Imgur, some use custom endpoints. A misconfigured upload URL produces a black screen crash; a missing resource produces an immediate NUI error.
Why isn't Twitter or social media loading on my FiveM phone?
Social media apps are self-contained with their own database tables. If the feed loads blank: check that phone_twitter or equivalent tables exist and have data, verify the NUI iframe loads without CORS errors (F8 devtools > Network tab), and confirm the player has a registered profile in phone_twitter_accounts. The most common fix is re-running the phone's SQL install file to create any missing app tables.
Why is the phone app store showing errors?
App store errors come from missing or corrupt app metadata in the phone_apps config/table. Each installable app needs a valid name, icon path, version, and enabled flag. Most commonly this is a config drift after a phone update β the phone expects new fields (like min_version or category) that the DB migration didn't add. Re-run the phone's migration SQL to align schema with the current version.
Why isn't GPS working on my FiveM phone?
Phone GPS uses SetNewWaypoint(x, y) client-side. If setting a destination does nothing, verify the coordinates being passed are valid numbers (not nil, not NaN), and check for other scripts calling DeleteWaypoint or clearing waypoints on a loop. Some HUD scripts and minimap replacements interfere with waypoints β disable them temporarily to isolate.
