This tutorial explains how to overlay a dynamic datetime stamp in the format DD-MM-YYYY (e.g., 03-05-2025) on your webcam feed in OBS Studio, creating a CCTV-style look, and broadcast it as a virtual webcam. The datetime updates every second using a Lua script.
Requirements
-
OBS Studio: Version 26.1 or newer (download from obsproject.com).
-
Webcam: A connected webcam recognized by OBS.
-
Lua Script: A custom script to display the updating datetime.

- Save the Script:
- Copy the script content below into a file named cctv.lua.
- Place it in your OBS scripts folder:
- Windows: C:\Program Files\obs-studio\data\obs-plugins\frontend-tools\scripts
- macOS: ~/Library/Application Support/obs-studio/scripts
- Linux: ~/.config/obs-studio/scripts
- Set Up OBS:
- Open OBS Studio.
- Create a scene and add your webcam as a Video Capture Device source.
- Add a Text (GDI+/FreeType2) source (e.g., named “Timestamp”) and configure its appearance (e.g., font: Courier New, white text, black outline, positioned in the top-left corner).
- Load the Script:
- Go to Tools > Scripts in OBS.
- Click the “+” button, select realtime_clock.lua, and load it.
- In the script properties, set the “Text Source” to your text source (e.g., “Timestamp”).
-
Performance: The script is lightweight and shouldn’t affect OBS performance.
-
Customization: To include time (e.g., DD-MM-YYYY HH:MM:SS), modify the os.date format in the script to “%d-%m-%Y %H:%M:%S”.
This setup creates a professional CCTV-style webcam feed with a dynamic DD-MM-YYYY datetime overlay, perfect for streaming or video calls via OBS’s virtual webcam.
cctv.lua
obs = obslua
source_name = ""
activated = false
-- Function to set the time text
function set_time_text()
local text = os.date("%Y-%m-%d %H:%M:%S")
local source = obs.obs_get_source_by_name(source_name)
if source ~= nil then
local settings = obs.obs_data_create()
obs.obs_data_set_string(settings, "text", text)
obs.obs_source_update(source, settings)
obs.obs_data_release(settings)
obs.obs_source_release(source)
end
end
-- Timer callback to update time every second
function timer_callback()
set_time_text()
end
-- Activate or deactivate the timer
function activate(activating)
if activated == activating then
return
end
activated = activating
if activating then
set_time_text()
obs.timer_add(timer_callback, 1000)
else
obs.timer_remove(timer_callback)
end
end
-- Called when a source is activated/deactivated
function source_activated(cd)
local source = obs.calldata_source(cd, "source")
if source ~= nil then
local name = obs.obs_source_get_name(source)
if name == source_name then
activate(true)
end
end
end
function source_deactivated(cd)
local source = obs.calldata_source(cd, "source")
if source ~= nil then
local name = obs.obs_source_get_name(source)
if name == source_name then
activate(false)
end
end
end
-- Defines the properties that the user can change
function script_properties()
local props = obs.obs_properties_create()
local p = obs.obs_properties_add_list(props, "source", "Text Source", obs.OBS_COMBO_TYPE_EDITABLE, obs.OBS_COMBO_FORMAT_STRING)
local sources = obs.obs_enum_sources()
if sources ~= nil then
for _, source in ipairs(sources) do
source_id = obs.obs_source_get_unversioned_id(source)
if source_id == "text_gdiplus" or source_id == "text_ft2_source" then
local name = obs.obs_source_get_name(source)
obs.obs_property_list_add_string(p, name, name)
end
end
end
obs.source_list_release(sources)
return props
end
-- Returns the description shown to the user
function script_description()
return "Sets a text source to display the current local machine time in the format YYYY-MM-DD HH:MM:SS.\n\nModified from a script by Lain"
end
-- Called when settings are changed
function script_update(settings)
activate(false)
source_name = obs.obs_data_get_string(settings, "source")
local source = obs.obs_get_source_by_name(source_name)
if source ~= nil then
local active = obs.obs_source_active(source)
obs.obs_source_release(source)
activate(active)
end
end
-- Called to set default settings
function script_defaults(settings)
end
-- Called on script startup
function script_load(settings)
local sh = obs.obs_get_signal_handler()
obs.signal_handler_connect(sh, "source_activate", source_activated)
obs.signal_handler_connect(sh, "source_deactivate", source_deactivated)
end
Tiếng Việt

