Index: binary-improvements2/MapRendering/Web/API/GetWebMods.cs
===================================================================
--- binary-improvements2/MapRendering/Web/API/GetWebMods.cs	(revision 384)
+++ binary-improvements2/MapRendering/Web/API/GetWebMods.cs	(revision 384)
@@ -0,0 +1,39 @@
+using AllocsFixes.JSON;
+using HttpListenerRequest = SpaceWizards.HttpListener.HttpListenerRequest;
+using HttpListenerResponse = SpaceWizards.HttpListener.HttpListenerResponse;
+
+namespace AllocsFixes.NetConnections.Servers.Web.API {
+	public class GetWebMods : WebAPI {
+		private readonly JSONArray loadedWebMods = new JSONArray ();
+
+		public GetWebMods (Web _parent) {
+			foreach (WebMod webMod in _parent.webMods) {
+				JSONObject modJson = new JSONObject ();
+
+				modJson.Add ("name", new JSONString (webMod.ParentMod.ModInfo.Name.Value));
+				
+				string webModReactBundle = webMod.ReactBundle;
+				if (webModReactBundle != null) {
+					modJson.Add ("bundle", new JSONString (webModReactBundle));
+				}
+
+				string webModCssFile = webMod.CssPath;
+				if (webModCssFile != null) {
+					modJson.Add ("css", new JSONString (webModCssFile));
+				}
+
+				loadedWebMods.Add (modJson);
+			}
+		}
+
+		public override void HandleRequest (HttpListenerRequest _req, HttpListenerResponse _resp, WebConnection _user,
+			int _permissionLevel) {
+
+			WriteJSON (_resp, loadedWebMods);
+		}
+
+		public override int DefaultPermissionLevel () {
+			return 2000;
+		}
+	}
+}
Index: binary-improvements2/MapRendering/Web/Handlers/ApiHandler.cs
===================================================================
--- binary-improvements2/MapRendering/Web/Handlers/ApiHandler.cs	(revision 383)
+++ binary-improvements2/MapRendering/Web/Handlers/ApiHandler.cs	(revision 384)
@@ -11,11 +11,29 @@
 		private readonly Dictionary<string, WebAPI> apis = new CaseInsensitiveStringDictionary<WebAPI> ();
 
-		public ApiHandler (string _moduleName = null) : base (_moduleName) {
+		public ApiHandler () : base (null) {
 
+		}
+
+		public override void SetBasePathAndParent (Web _parent, string _relativePath) {
+			base.SetBasePathAndParent (_parent, _relativePath);
+
+			Type[] apiWithParentCtorTypes = { typeof (Web) };
+			Object[] apiWithParentCtorArgs = { _parent };
+
+			Type[] apiEmptyCtorTypes = { };
+			Object[] apiEmptyCtorArgs = { };
+			
 			foreach (Type t in Assembly.GetExecutingAssembly ().GetTypes ()) {
 				if (!t.IsAbstract && t.IsSubclassOf (typeof (WebAPI))) {
-					ConstructorInfo ctor = t.GetConstructor (new Type [0]);
+					ConstructorInfo ctor = t.GetConstructor (apiWithParentCtorTypes);
 					if (ctor != null) {
-						WebAPI apiInstance = (WebAPI) ctor.Invoke (new object [0]);
+						WebAPI apiInstance = (WebAPI) ctor.Invoke (apiWithParentCtorArgs);
+						addApi (apiInstance);
+						continue;
+					}
+					
+					ctor = t.GetConstructor (apiEmptyCtorTypes);
+					if (ctor != null) {
+						WebAPI apiInstance = (WebAPI) ctor.Invoke (apiEmptyCtorArgs);
 						addApi (apiInstance);
 					}
Index: binary-improvements2/MapRendering/Web/Web.cs
===================================================================
--- binary-improvements2/MapRendering/Web/Web.cs	(revision 383)
+++ binary-improvements2/MapRendering/Web/Web.cs	(revision 384)
@@ -17,5 +17,5 @@
 	public class Web : IConsoleServer {
 		private const int guestPermissionLevel = 2000;
-		private const string indexPagePath = "/app";
+		private const string indexPageUrl = "/app";
 		
 		public static int handlingCount;
@@ -23,4 +23,5 @@
 		public static long totalHandlingTime = 0;
 		private readonly List<AbsHandler> handlers = new List<AbsHandler> ();
+		public readonly List<WebMod> webMods = new List<WebMod> ();
 		private readonly ConnectionHandler connectionHandler;
 
@@ -64,20 +65,23 @@
 				);
 				
+				// Do mods relatively early as they should not be requested a lot, unlike the later registrations, especially for API and map tiles
+				RegisterWebMods (useStaticCache);
+
 				RegisterPathHandler ("/session/", new SessionHandler (webfilesFolder, connectionHandler));
 				RegisterPathHandler ("/userstatus", new UserStatusHandler ());
+				RegisterPathHandler ("/sse/", new SseHandler ());
 				RegisterPathHandler ("/files/", new StaticHandler (
-						webfilesFolder,
-						useStaticCache ? (AbstractCache) new SimpleCache () : new DirectAccess (),
-						false)
+					webfilesFolder,
+					useStaticCache ? (AbstractCache) new SimpleCache () : new DirectAccess (),
+					false)
 				);
 				RegisterPathHandler ("/itemicons/", new ItemIconHandler (true));
 				RegisterPathHandler ("/map/", new StaticHandler (
-						GameIO.GetSaveGameDir () + "/map",
-						MapRendering.MapRendering.GetTileCache (),
-						false,
-						"web.map")
+					GameIO.GetSaveGameDir () + "/map",
+					MapRendering.MapRendering.GetTileCache (),
+					false,
+					"web.map")
 				);
 				RegisterPathHandler ("/api/", new ApiHandler ());
-				RegisterPathHandler ("/sse/", new SseHandler ());
 
 				listener.Prefixes.Add ($"http://+:{webPort}/");
@@ -105,4 +109,25 @@
 			handlers.Add (_handler);
 			_handler.SetBasePathAndParent (this, _urlBasePath);
+		}
+
+		private void RegisterWebMods (bool _useStaticCache) {
+			foreach (Mod mod in ModManager.GetLoadedMods ()) {
+				try {
+					string webModPath = mod.Path + "/WebMod";
+					if (!Directory.Exists (webModPath)) {
+						continue;
+					}
+
+					try {
+						WebMod webMod = new WebMod (this, mod, _useStaticCache);
+						webMods.Add (webMod);
+					} catch (InvalidDataException e) {
+						Log.Error ($"Could not load webmod from mod {mod.ModInfo.Name.Value}: {e.Message}");
+					}
+				} catch (Exception e) {
+					Log.Error ("Failed loading web mods from mod " + mod.ModInfo.Name.Value);
+					Log.Exception (e);
+				}
+			}
 		}
 
@@ -198,5 +223,5 @@
 
 				if (requestPath.Length < 2) {
-					response.Redirect (indexPagePath);
+					response.Redirect (indexPageUrl);
 					return;
 				}
Index: binary-improvements2/MapRendering/Web/WebMod.cs
===================================================================
--- binary-improvements2/MapRendering/Web/WebMod.cs	(revision 384)
+++ binary-improvements2/MapRendering/Web/WebMod.cs	(revision 384)
@@ -0,0 +1,50 @@
+using System.IO;
+using AllocsFixes.FileCache;
+using AllocsFixes.NetConnections.Servers.Web.Handlers;
+
+namespace AllocsFixes.NetConnections.Servers.Web {
+	public class WebMod {
+		private const string modsBaseUrl = "/webmods/";
+		private const string reactBundleName = "bundle.js";
+		private const string stylingFileName = "styling.css";
+		
+		public readonly Mod ParentMod;
+		public readonly string ReactBundle; // Absolute web path to the React bundle if the mod has one, e.g. "/webmods/myMod/bundle.js"
+		public readonly string CssPath; // Absolute web path to a CSS if the mod has one, e.g. "/webmods/myMod/styling.css";
+
+		public WebMod (Web _parentWeb, Mod _parentMod, bool _useStaticCache) {
+			string folder = _parentMod.Path + "/WebMod";
+			if (!Directory.Exists (folder)) {
+				throw new InvalidDataException("No WebMod folder in mod");
+			}
+
+			string urlWebModBase = $"{modsBaseUrl}{_parentMod.FolderName}/";
+
+			ReactBundle = folder + "/" + reactBundleName;
+			if (File.Exists (ReactBundle)) {
+				ReactBundle = urlWebModBase + reactBundleName;
+			} else {
+				ReactBundle = null;
+			}
+
+			CssPath = folder + "/" + stylingFileName;
+			if (File.Exists (CssPath)) {
+				CssPath = urlWebModBase + stylingFileName;
+			} else {
+				CssPath = null;
+			}
+
+			if (ReactBundle == null && CssPath == null) {
+				throw new InvalidDataException($"WebMod folder has neither a {reactBundleName} nor a {stylingFileName}");
+			}
+
+			ParentMod = _parentMod;
+
+			_parentWeb.RegisterPathHandler (urlWebModBase, new StaticHandler (
+				folder,
+				_useStaticCache ? (AbstractCache) new SimpleCache () : new DirectAccess (),
+				false)
+			);
+		}
+	}
+}
Index: binary-improvements2/MapRendering/WebAndMapRendering.csproj
===================================================================
--- binary-improvements2/MapRendering/WebAndMapRendering.csproj	(revision 383)
+++ binary-improvements2/MapRendering/WebAndMapRendering.csproj	(revision 384)
@@ -87,4 +87,5 @@
     <Compile Include="Web\API\GetAnimalsLocation.cs" />
     <Compile Include="Web\API\GetHostileLocation.cs" />
+    <Compile Include="Web\API\GetWebMods.cs" />
     <Compile Include="Web\API\Null.cs" />
     <Compile Include="Web\Handlers\RewriteHandler.cs" />
@@ -104,4 +105,5 @@
     <Compile Include="Web\OpenID.cs" />
     <Compile Include="Web\ConnectionHandler.cs" />
+    <Compile Include="Web\WebMod.cs" />
     <Compile Include="Web\WebPermissions.cs" />
     <Compile Include="Web\Handlers\ApiHandler.cs" />
