diff --git a/API/Api.cs b/API/Api.cs
new file mode 100644
index 0000000..809fc9e
--- /dev/null
+++ b/API/Api.cs
@@ -0,0 +1,41 @@
+using SQLiteEF;
+
+namespace API;
+
+public class Api
+{
+    public Api(string[] args)
+    {
+        WebApplicationBuilder builder = WebApplication.CreateBuilder(args);
+
+        // Add services to the container.
+
+        builder.Services.AddControllers();
+        // Learn more about configuring OpenAPI at https://aka.ms/aspnet/openapi
+        builder.Services.AddOpenApi();
+
+        builder.Services.AddDbContext<Context>();
+
+        WebApplication app = builder.Build();
+
+        // Configure the HTTP request pipeline.
+        if (app.Environment.IsDevelopment())
+        {
+            app.MapOpenApi();
+        }
+
+        app.UseHttpsRedirection();
+
+        app.UseAuthorization();
+
+
+        app.MapControllers();
+
+        app.Run();
+    }
+    
+    public static void Main(string[] args)
+    {
+        Api _ = new (args);
+    }
+}
\ No newline at end of file
diff --git a/API/Properties/launchSettings.json b/API/Properties/launchSettings.json
new file mode 100644
index 0000000..e25a4ca
--- /dev/null
+++ b/API/Properties/launchSettings.json
@@ -0,0 +1,23 @@
+{
+  "$schema": "https://json.schemastore.org/launchsettings.json",
+  "profiles": {
+    "http": {
+      "commandName": "Project",
+      "dotnetRunMessages": true,
+      "launchBrowser": false,
+      "applicationUrl": "http://localhost:5239",
+      "environmentVariables": {
+        "ASPNETCORE_ENVIRONMENT": "Development"
+      }
+    },
+    "https": {
+      "commandName": "Project",
+      "dotnetRunMessages": true,
+      "launchBrowser": false,
+      "applicationUrl": "https://localhost:7103;http://localhost:5239",
+      "environmentVariables": {
+        "ASPNETCORE_ENVIRONMENT": "Development"
+      }
+    }
+  }
+}
diff --git a/API/appsettings.Development.json b/API/appsettings.Development.json
new file mode 100644
index 0000000..0c208ae
--- /dev/null
+++ b/API/appsettings.Development.json
@@ -0,0 +1,8 @@
+{
+  "Logging": {
+    "LogLevel": {
+      "Default": "Information",
+      "Microsoft.AspNetCore": "Warning"
+    }
+  }
+}
diff --git a/API/appsettings.json b/API/appsettings.json
new file mode 100644
index 0000000..10f68b8
--- /dev/null
+++ b/API/appsettings.json
@@ -0,0 +1,9 @@
+{
+  "Logging": {
+    "LogLevel": {
+      "Default": "Information",
+      "Microsoft.AspNetCore": "Warning"
+    }
+  },
+  "AllowedHosts": "*"
+}
diff --git a/Run/Program.cs b/Run/Program.cs
new file mode 100644
index 0000000..546589b
--- /dev/null
+++ b/Run/Program.cs
@@ -0,0 +1,12 @@
+using API;
+
+namespace Run;
+
+class Program
+{
+    static void Main(string[] args)
+    {
+        Api a = new (args);
+        Tracker.Tracker t = new ();     
+    }
+}
\ No newline at end of file
diff --git a/Run/Run.csproj b/Run/Run.csproj
new file mode 100644
index 0000000..1c8f52c
--- /dev/null
+++ b/Run/Run.csproj
@@ -0,0 +1,16 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+    <PropertyGroup>
+        <OutputType>Exe</OutputType>
+        <TargetFramework>net9.0</TargetFramework>
+        <LangVersion>latest</LangVersion>
+        <ImplicitUsings>enable</ImplicitUsings>
+        <Nullable>enable</Nullable>
+    </PropertyGroup>
+
+    <ItemGroup>
+      <ProjectReference Include="..\API\API.csproj" />
+      <ProjectReference Include="..\Tracker\Tracker.csproj" />
+    </ItemGroup>
+
+</Project>
diff --git a/SQLiteEF/Player.cs b/SQLiteEF/Player.cs
new file mode 100644
index 0000000..db048f3
--- /dev/null
+++ b/SQLiteEF/Player.cs
@@ -0,0 +1,38 @@
+using Microsoft.EntityFrameworkCore;
+
+namespace SQLiteEF;
+
+[PrimaryKey("SteamId")]
+public class Player : IUpdateable
+{
+    public ulong SteamId { get; init; }
+    public string Name { get; set; }
+    public string ProfileUrl { get; set; }
+    public string AvatarUrl { get; set; }
+    
+    public ICollection<Game> Games { get; init; } = null!;
+    public ICollection<TrackedTime> TrackedTimes { get; init; } = null!;
+    public DateTime UpdatedAt { get; set; } = DateTime.Now;
+
+    public Player(ulong steamid, string name, string profileUrl, string avatarUrl)
+    {
+        this.SteamId = steamid;
+        this.Name = name;
+        this.ProfileUrl = profileUrl;
+        this.AvatarUrl = avatarUrl;
+        this.Games = [];
+        this.TrackedTimes = [];
+    }
+    
+    /// <summary>
+    /// EF CORE
+    /// </summary>
+    internal Player(ulong steamid, string name, string profileUrl, string avatarUrl, DateTime updatedAt)
+    {
+        this.SteamId = steamid;
+        this.Name = name;
+        this.ProfileUrl = profileUrl;
+        this.AvatarUrl = avatarUrl;
+        this.UpdatedAt = updatedAt;
+    }
+}
\ No newline at end of file
diff --git a/SQLiteEF/SQLiteEF.csproj b/SQLiteEF/SQLiteEF.csproj
new file mode 100644
index 0000000..1211f9b
--- /dev/null
+++ b/SQLiteEF/SQLiteEF.csproj
@@ -0,0 +1,14 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+    <PropertyGroup>
+        <TargetFramework>net9.0</TargetFramework>
+        <ImplicitUsings>enable</ImplicitUsings>
+        <Nullable>enable</Nullable>
+    </PropertyGroup>
+
+    <ItemGroup>
+      <PackageReference Include="Microsoft.EntityFrameworkCore" Version="9.0.5" />
+      <PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="9.0.5" />
+    </ItemGroup>
+
+</Project>
diff --git a/Tracker/Tracker.cs b/Tracker/Tracker.cs
new file mode 100644
index 0000000..b399ad3
--- /dev/null
+++ b/Tracker/Tracker.cs
@@ -0,0 +1,155 @@
+using Microsoft.Extensions.Configuration;
+using SQLiteEF;
+using SteamApiWrapper.ReturnTypes;
+using SteamGame = SteamApiWrapper.ReturnTypes.Game;
+using Player = SQLiteEF.Player;
+using SteamPlayer = SteamApiWrapper.ReturnTypes.Player;
+using Steam = SteamApiWrapper.SteamApiWrapper;
+
+namespace Tracker;
+
+public class Tracker : IDisposable
+{
+    private IConfiguration Configuration { get; init; }
+    private readonly Thread _trackerThread;
+    private bool _running = true;
+
+    public Tracker()
+    {
+        Configuration = new ConfigurationBuilder()
+            .AddJsonFile("appsettings.json")
+            .Build();
+        _trackerThread = new (TrackerLoop);
+        _trackerThread.Start();
+    }
+
+    private void UpdatePlayers()
+    {
+        Context context = new (Configuration);
+        IQueryable<ulong> players = context.Players.Select(p => p.SteamId);
+        GetPlayerSummaries summaries = Steam.GetPlayerSummaries(players.ToArray());
+        foreach (SteamPlayer summariesPlayer in summaries.players)
+        {
+            if (context.Players.Find(summariesPlayer.steamid) is not { } player)
+            {
+                context.Players.Add(new (summariesPlayer.steamid, summariesPlayer.personaname,
+                    summariesPlayer.profileurl, summariesPlayer.avatar));
+                continue;
+            }
+            player.Name = summariesPlayer.personaname;
+            player.ProfileUrl = summariesPlayer.profileurl;
+            player.AvatarUrl = summariesPlayer.avatar;
+            try
+            {
+                context.SaveChanges();
+            }
+            catch (Exception e)
+            {
+                Console.WriteLine(e);
+            }
+        }
+    }
+
+    private void UpdateOwnedGames()
+    {
+        Context context = new (Configuration);
+        IQueryable<Player> players = context.Players;
+        foreach (Player player in players)
+        {
+            GetOwnedGames ownedGames = Steam.GetOwnedGames(player.SteamId);
+            foreach (SteamGame ownedGame in ownedGames.games)
+            {
+                if (context.Games.Find(ownedGame.appid) is not { } game)
+                {
+                    game = new(ownedGame.appid, ownedGame.name);
+                }
+
+                if (!player.Games.Contains(game))
+                {
+                    player.Games.Add(game);
+                    game.PlayedBy.Add(player);
+                    player.TrackedTimes.Add(new (game, player, ownedGame.playtime_forever));
+                }
+                
+                try
+                {
+                    context.SaveChanges();
+                }
+                catch (Exception e)
+                {
+                    Console.WriteLine(e);
+                }
+            }
+        }
+    }
+
+    private void UpdateGametimes()
+    {
+        Context context = new (Configuration);
+        IQueryable<Player> players = context.Players;
+        foreach (Player player in players)
+        {
+            GetRecentlyPlayedGames recentlyPlayed = Steam.GetRecentlyPlayedGames(player.SteamId);
+            foreach (SteamGame recentlyPlayedGame in recentlyPlayed.games)
+            {
+                if (context.Games.Find(recentlyPlayedGame.appid) is not { } game)
+                {
+                    game = new(recentlyPlayedGame.appid, recentlyPlayedGame.name);
+                }
+
+                if (!player.Games.Contains(game))
+                {
+                    player.Games.Add(game);
+                    game.PlayedBy.Add(player);
+                }
+                
+                player.TrackedTimes.Add(new (game, player, recentlyPlayedGame.playtime_forever));
+                
+                try
+                {
+                    context.SaveChanges();
+                }
+                catch (Exception e)
+                {
+                    Console.WriteLine(e);
+                }
+            }
+        }
+    }
+
+    private void TrackerLoop()
+    {
+        while (_running)
+        {
+            try
+            {
+                Thread.Sleep(TimeSpan.FromHours(1));
+            }
+            catch (ThreadInterruptedException)
+            {
+                Console.WriteLine("Thread interrupted");
+            }
+            catch (ThreadAbortException)
+            {
+                _running = false;
+            }
+        }
+        Console.WriteLine("Thread exited");
+    }
+
+    public void ForceLoop()
+    {
+        _trackerThread.Interrupt();
+    }
+    
+    static void Main(string[] args)
+    {
+        Tracker _ = new ();
+    }
+
+    public void Dispose()
+    {
+        _running = false;
+        _trackerThread.Interrupt();
+    }
+}
\ No newline at end of file
diff --git a/Tracker/Tracker.csproj b/Tracker/Tracker.csproj
new file mode 100644
index 0000000..c46201b
--- /dev/null
+++ b/Tracker/Tracker.csproj
@@ -0,0 +1,21 @@
+<Project Sdk="Microsoft.NET.Sdk">
+
+    <PropertyGroup>
+        <OutputType>Exe</OutputType>
+        <TargetFramework>net9.0</TargetFramework>
+        <LangVersion>latest</LangVersion>
+        <ImplicitUsings>enable</ImplicitUsings>
+        <Nullable>enable</Nullable>
+    </PropertyGroup>
+
+    <ItemGroup>
+      <ProjectReference Include="..\SQLiteEF\SQLiteEF.csproj" />
+      <ProjectReference Include="..\SteamApiWrapper\SteamApiWrapper.csproj" />
+    </ItemGroup>
+
+    <ItemGroup>
+      <PackageReference Include="Microsoft.Extensions.Configuration" Version="9.0.5" />
+      <PackageReference Include="Microsoft.Extensions.Configuration.Json" Version="9.0.5" />
+    </ItemGroup>
+
+</Project>