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