Open-source project
PhantomGamers/SFP avatar
PhantomGamers/SFP

SFP reskins the modern Steam client by injecting into CEF

This utility is designed to allow you to apply skins to the modern Steam client

654 stars11 forksC#MIT

At a glance

What is it?
SFP, formerly SteamFriendsPatcher, applies custom CSS and JavaScript to the modern Steam client by starting Steam with the -cef-enable-debugging argument and injecting into its Chromium pages. It is a small .NET utility for people who want the old skinning workflow back, and its versioning is still in the 0.0.x range.
Who is it for?
Adopt SFP if you want to theme the modern Steam client with CSS and JavaScript, you are comfortable granting a third party tool access to your Steam session, and you accept that a Steam client update can break your skin. Do not adopt it as a productivity tool, since it does nothing beyond theming, and do not enable its JavaScript injection without reading what you install, because the README warns that injected code can be malicious.
Can I use it commercially?
Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
Is it still maintained?
Yes. The repository last received commits 59 days ago.
What is it written in?
Mainly C#, according to GitHub's language statistics.

Answers come from the project's GitHub data, last synced on October 23, 2026, and from our analysis. They are not legal advice.

Editorial analysis

The old skinning trick applied to the new client

SFP was formerly called SteamFriendsPatcher, and the rename is the whole story of the project. SteamFriendsPatcher was a utility for the old Steam client, where replacing a stylesheet was enough to reskin the interface. The modern Steam client renders its pages with Chromium Embedded Framework, and simply writing a custom CSS file into the Steam directory no longer does anything.

SFP's approach is to go back to the CEF debugging switch. The README states that Steam must be running with the -cef-enable-debugging argument for SFP to work, and that if Steam is started with SFP it does this automatically. If you start Steam yourself, there is a Force Steam arguments setting, which is enabled by default and will automatically restart Steam with the chosen arguments if it does not already have them.

The security posture follows from that mechanism, and the README is unusually direct about it. The injector has to be running as long as Steam is running, for full functionality. In other words, this is not a one-off patch that you apply and forget. A tool is continuously attached to your Steam client, in a debug mode, and it can inject JavaScript into the pages Steam renders.

The repository topic list names reverse-engineering, skin, steam, steam-client, theme and valve, and the primary language is recorded as C#. The layout is a .NET solution, SFP.slnx, with an SFP project, an SFP_UI project for the user interface, shared properties in SFPCommon.props and Directory.Packages.props, and a createpublishedzip.ps1 script that produces the release archives. The licence is MIT.

Four CSS targets and four matching JavaScript targets

The default routing is the part worth understanding, because it explains what a skin can and cannot reach.

Skins for the Steam client, the library and the overlay go in Steam/steamui/libraryroot.custom.css. Skins for the friends list and the chat windows go in Steam/steamui/friends.custom.css. Skins for the Steam store and the community pages go in Steam/steamui/webkit.css. And skins for Big Picture Mode go in Steam/steamui/bigpicture.custom.css.

Each of those has a JavaScript counterpart with the same base name and a .js extension, so libraryroot.custom.js, friends.custom.js, webkit.js and bigpicture.custom.js. The features section describes this as reading and applying custom CSS to Steam pages, and reading and applying custom JavaScript to Steam pages, with the ability to customize which files apply to which pages in the skin config.

The split reflects how the client is built. The library and overlay, the friends UI, the webkit based store and community pages, and the Big Picture mode are separate documents in the client, and each is a separate injection target. A skin that only restyles the library will not touch the store, which is why skin authors need the routing mechanism rather than a single stylesheet.

There is also a second location. Skins and scripts can be added to their own folders within Steam/steamui/skins and then selected in SFP's settings, which is how a skin author ships a package rather than a loose set of files.

skin.json decides which file reaches which page

If a skin folder contains a skin.json file in its root, that file takes over the routing. The default file is a list of patch entries, and each entry has a MatchRegexString that is matched against a Steam page title, or against a URL when the string begins with http:// or https://, and optional TargetCss and TargetJs keys naming the files to apply when the regex matches.

An entry can carry both a CSS target and a JS target, or just one of them. A single entry from the default configuration looks like this:

json
    {
      "MatchRegexString": "^Steam$",
      "TargetCss": "libraryroot.custom.css",
      "TargetJs": "libraryroot.custom.js"
    },

The default file covers a long list of targets, among them the store and community URL patterns, the Steam root page, the overlay browser, the SP Overlay pages, the supernav, the notification toasts, the find browser and the overlay find tabs, Big Picture Mode and its quick access and main menu pages, the friends UI container, menus, and the modal dialog and full modal overlay popups.

Two rules govern the behaviour and they are easy to get wrong. Each target can only have one CSS file and one JavaScript file injected at a time, and the first match takes precedence, so the order of the patches matters. A second entry that also matches the same page will not add another file, it will be ignored.

If you want the default routing and do not want to write your own file, you omit skin.json entirely or include the short form:

json
{
    "UseDefaultPatches": true
}

JavaScript injection is off until you turn it on

The scripting feature exists and is gated, and the gate is the right way round.

The README says JavaScript injection is disabled by default and must be enabled in SFP's settings. It also says, in the same short list, that JavaScript code can potentially be malicious, so only install scripts from people you trust.

That is a sensible design for a tool that injects code into a logged in application. Injecting CSS is a cosmetic risk. Injecting JavaScript into a Steam page that has your session cookies is not, because the injected code runs with the same privileges as the page, and the page is authenticated. A script from an untrusted author is effectively running code in your Steam client, with your account, while you play.

The README also points to a Steam Skins Wiki for existing skins and links, which is where the trust question gets answered in practice. The skin ecosystem is community authored, and the scripts that ship with popular skins are the part of that ecosystem to read carefully rather than skim.

There is a further section for skin authors covering how to match against pages with variable titles, how to find Steam page titles, and how to use the system accent color. That last one matters for anyone writing a theme, because a skin that hardcodes a colour stops looking right the moment the user changes their system theme.

Running SFP: pick an archive and leave the injector alive

The installation steps are short and have one branch that catches people out.

You download and extract the latest zip file under Releases for your operating system. If you have .NET 7 installed, you download the _net7.zip release, and otherwise you download the _SelfContained.zip release. The distinction is whether the runtime is already on your machine or travels with the application.

Then you run the SFP_UI application. By default it waits for Steam to start and injects, or injects immediately if Steam is already running. The README is explicit that for full functionality SFP must be running with its injector started as long as Steam is running, which means the tool is part of your Steam session rather than a one-time operation.

The -cef-enable-debugging argument is the other half of the setup. If you launch Steam with SFP it will do this automatically. If you launch Steam yourself, the Force Steam arguments setting will restart Steam with the chosen arguments if it does not already have them, and that setting is enabled by default.

The last step is the Open File button in SFP, which opens the directories your custom skins and scripts are applied from, so you can drop files into the right place without hunting through the Steam installation path.

The README's table of contents also lists Todo, Known Issues, Dependencies with an All subsection and a Linux subsection, and a Credits section. Those sections are listed in the contents but their details are not spelled out in the README, which is exactly why they are worth reading on the repository page before you commit to the tool, since dependencies in particular decide whether the injector will run on your distribution.

Version 0.0.x is the honest signal about the project

The release history is short versions with high frequency, which is the signature of a utility that tracks a target it does not control.

Release 0.0.72 was published on 2026-08-25, 0.0.71 on 2026-08-05 and 0.0.70 on 2026-08-04. The last push was on 2026-08-25. Two releases in two days in August, with the most recent one on the same day as the last push, says the project reacts to Steam client changes as they land rather than following a release plan.

That is a reasonable rhythm for this kind of tool and a bad sign for a different kind of expectation. You are not depending on a stable API, you are depending on a patch that has to be reissued when Valve changes the client. The project is not promising otherwise, and the 0.0.x numbering is the clearest signal available that the surface is not settled.

The licence is MIT, which removes one category of concern. The repository also carries an .editorconfig, a .gitattributes, a .pre-commit-config.yaml, an .idea directory and a .github directory, which is the ordinary furniture of a project with an active contributor workflow.

For a skinner, the practical risk is not a licence question. It is a compatibility question, and the answer to it changes with every Steam update, which is why the release cadence looks the way it does.

Editorial conclusion

Adopt SFP if you want to theme the modern Steam client with CSS and JavaScript, you are comfortable granting a third party tool access to your Steam session, and you accept that a Steam client update can break your skin. Do not adopt it as a productivity tool, since it does nothing beyond theming, and do not enable its JavaScript injection without reading what you install, because the README warns that injected code can be malicious. Before you start, confirm you can pass the -cef-enable-debugging argument to Steam, and check the Known Issues and Dependencies sections of the README, which the contents list but whose details the README does not spell out.

Frequently asked questions

How do I install and run SFP to skin Steam?

Download the latest zip under Releases for your operating system, the _net7.zip build if you have .NET 7 installed or the _SelfContained.zip build otherwise, extract it and run SFP_UI. By default it waits for Steam to start and injects, or injects immediately if Steam is already running.

Why does SFP need Steam to run with -cef-enable-debugging?

SFP injects CSS and JavaScript into the Chromium pages the modern Steam client renders, and that debugging argument is what makes those pages reachable. If Steam is started through SFP the argument is added automatically, and the Force Steam arguments setting, enabled by default, restarts Steam with it otherwise.

How do I control which skin files apply to which Steam pages?

Add a skin.json file in the root of your skin folder. Each entry has a MatchRegexString matched against a Steam page title or a URL, plus optional TargetCss and TargetJs keys. Only one CSS and one JavaScript file can be injected per target, and the first matching entry wins, so the order of the patches matters.

Is JavaScript injection enabled by default in SFP?

No. The README says JavaScript injection is disabled by default and must be enabled in SFP's settings, and warns that injected JavaScript can potentially be malicious, so scripts should only be installed from sources you trust.

Official sources

  1. Issues
  2. License: MIT
  3. PhantomGamers/SFP on GitHub
  4. README
  5. Releases
Add this badge to your README

If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.

Add this badge to your README

markdown
[![Hysen Labs](https://hysenlabs.com/badge/phantomgamers-sfp.svg)](https://hysenlabs.com/projects/phantomgamers-sfp)

Was this useful?