diff --git a/client/src/main/java/ctbrec/ui/sites/jasmin/LiveJasminFollowedTab.java b/client/src/main/java/ctbrec/ui/sites/jasmin/LiveJasminFollowedTab.java
index 50c65017..330b8cc9 100644
--- a/client/src/main/java/ctbrec/ui/sites/jasmin/LiveJasminFollowedTab.java
+++ b/client/src/main/java/ctbrec/ui/sites/jasmin/LiveJasminFollowedTab.java
@@ -2,9 +2,13 @@ package ctbrec.ui.sites.jasmin;
 
 import ctbrec.sites.jasmin.LiveJasmin;
 import ctbrec.ui.tabs.FollowedTab;
+import javafx.geometry.Insets;
 import javafx.scene.Scene;
+import javafx.scene.control.RadioButton;
+import javafx.scene.control.ToggleGroup;
 import javafx.scene.input.KeyCode;
 import javafx.scene.input.KeyEvent;
+import javafx.scene.layout.HBox;
 
 public class LiveJasminFollowedTab extends LiveJasminTab implements FollowedTab {
 
@@ -20,4 +24,28 @@ public class LiveJasminFollowedTab extends LiveJasminTab implements FollowedTab
             }
         });
     }
+
+    @Override
+    protected void createGui() {
+        super.createGui();
+        addOnlineOfflineSelector();
+    }
+
+    private void addOnlineOfflineSelector() {
+        var group = new ToggleGroup();
+        var online = new RadioButton("online");
+        online.setToggleGroup(group);
+        var offline = new RadioButton("offline");
+        offline.setToggleGroup(group);
+        pagination.getChildren().add(online);
+        pagination.getChildren().add(offline);
+        HBox.setMargin(online, new Insets(5,5,5,40));
+        HBox.setMargin(offline, new Insets(5,5,5,5));
+        online.setSelected(true);
+        group.selectedToggleProperty().addListener(e -> {
+            ((LiveJasminFollowedUpdateService)updateService).setShowOnline(online.isSelected());
+            queue.clear();
+            updateService.restart();
+        });
+    }
 }
diff --git a/client/src/main/java/ctbrec/ui/sites/jasmin/LiveJasminFollowedUpdateService.java b/client/src/main/java/ctbrec/ui/sites/jasmin/LiveJasminFollowedUpdateService.java
index c18ac97c..70ccb271 100644
--- a/client/src/main/java/ctbrec/ui/sites/jasmin/LiveJasminFollowedUpdateService.java
+++ b/client/src/main/java/ctbrec/ui/sites/jasmin/LiveJasminFollowedUpdateService.java
@@ -1,38 +1,42 @@
 package ctbrec.ui.sites.jasmin;
 
-import static ctbrec.io.HtmlParser.*;
 import static ctbrec.io.HttpConstants.*;
 
 import java.io.IOException;
 import java.util.ArrayList;
+import java.util.LinkedList;
 import java.util.List;
 import java.util.Locale;
+import java.util.concurrent.Future;
 
-import org.jsoup.nodes.Element;
-import org.jsoup.select.Elements;
+import org.json.JSONArray;
+import org.json.JSONObject;
 import org.slf4j.Logger;
 import org.slf4j.LoggerFactory;
 
 import ctbrec.Config;
+import ctbrec.GlobalThreadPool;
 import ctbrec.Model;
-import ctbrec.NotLoggedInExcetion;
 import ctbrec.io.HttpException;
 import ctbrec.sites.jasmin.LiveJasmin;
 import ctbrec.sites.jasmin.LiveJasminModel;
 import ctbrec.ui.SiteUiFactory;
 import ctbrec.ui.tabs.PaginatedScheduledService;
 import javafx.concurrent.Task;
+import okhttp3.HttpUrl;
 import okhttp3.Request;
+import okhttp3.Response;
 
 public class LiveJasminFollowedUpdateService extends PaginatedScheduledService {
 
     private static final Logger LOG = LoggerFactory.getLogger(LiveJasminFollowedUpdateService.class);
     private LiveJasmin liveJasmin;
     private String url;
+    private boolean showOnline = true;
 
     public LiveJasminFollowedUpdateService(LiveJasmin liveJasmin) {
         this.liveJasmin = liveJasmin;
-        this.url = liveJasmin.getBaseUrl() + "/en/member/favorite";
+        this.url = liveJasmin.getBaseUrl() + "/en/free/favourite/get-favourite-list";
     }
 
     @Override
@@ -40,34 +44,64 @@ public class LiveJasminFollowedUpdateService extends PaginatedScheduledService {
         return new Task<List<Model>>() {
             @Override
             public List<Model> call() throws IOException {
-                if (!liveJasmin.credentialsAvailable()) {
-                    throw new NotLoggedInExcetion("Credentials missing");
+                if(!liveJasmin.credentialsAvailable()) {
+                    throw new RuntimeException("Credentials missing");
                 }
 
                 boolean loggedIn = SiteUiFactory.getUi(liveJasmin).login();
-                if (!loggedIn) {
-                    throw new NotLoggedInExcetion("Couldn't login to livejasmin");
+                if(!loggedIn) {
+                    throw new RuntimeException("Couldn't login to livejasmin");
                 }
-                LOG.debug("Fetching page {}", url);
-                var request = new Request.Builder()
+                Request request = new Request.Builder()
                         .url(url)
                         .header(USER_AGENT, Config.getInstance().getSettings().httpUserAgent)
                         .header(ACCEPT, "*/*")
                         .header(ACCEPT_LANGUAGE, Locale.ENGLISH.getLanguage())
-                        .header(REFERER, liveJasmin.getBaseUrl())
+                        .header(REFERER, liveJasmin.getBaseUrl() + "/en/free/favorite")
+                        .header(X_REQUESTED_WITH, XML_HTTP_REQUEST)
                         .build();
-                try (var response = liveJasmin.getHttpClient().execute(request)) {
+                try (Response response = liveJasmin.getHttpClient().execute(request)) {
                     if (response.isSuccessful()) {
-                        var body = response.body().string();
+                        String body = response.body().string();
                         List<Model> models = new ArrayList<>();
-                        Elements modelCells = getTags(body, "article[class~=perf_container]");
-                        for (Element modelCell : modelCells) {
-                            String cellHtml = modelCell.html();
-                            String name = getText(cellHtml, "span[class~=performer_name_simple]").trim();
-                            LiveJasminModel model = (LiveJasminModel) liveJasmin.createModel(name);
-                            model.setPreview(getTag(cellHtml, "img[class~=performer-image]").attr("data-src"));
-                            model.setId(getTag(cellHtml, "span[class~=remove][class~=favorite]").attr("data-model-id"));
-                            models.add(model);
+                        JSONObject json = new JSONObject(body);
+                        if (json.has("success")) {
+                            JSONObject data = json.getJSONObject("data");
+                            JSONArray performers = data.getJSONArray("performers");
+                            List<Future<?>> loadDetailsFutures = new LinkedList<>();
+                            for (int i = 0; i < performers.length(); i++) {
+                                JSONObject m = performers.getJSONObject(i);
+                                String name = m.optString("pid");
+                                if (name.isEmpty()) {
+                                    continue;
+                                }
+
+                                LiveJasminModel model = (LiveJasminModel) liveJasmin.createModel(name);
+                                model.setId(m.getString("id"));
+                                model.setDisplayName(m.getString("display_name"));
+                                Model.State onlineState = LiveJasminModel.mapStatus(m.getInt("status"));
+                                boolean online = onlineState == Model.State.ONLINE;
+                                model.setOnlineState(onlineState);
+                                if (online == showOnline) {
+                                    models.add(model);
+                                }
+                                loadDetailsFutures.add(GlobalThreadPool.submit(() -> {
+                                    loadModelDetails(model);
+                                }));
+                            }
+                            for (Future<?> future : loadDetailsFutures) {
+                                try {
+                                    future.get();
+                                } catch (InterruptedException e) {
+                                    Thread.currentThread().interrupt();
+                                } catch (Exception e) {
+                                    // details couldn't be loaded, but that doesn't matter
+                                }
+                            }
+                            LOG.debug("done");
+                        } else {
+                            LOG.error("Request failed:\n{}", body);
+                            throw new IOException("Response was not successful");
                         }
                         return models;
                     } else {
@@ -75,6 +109,35 @@ public class LiveJasminFollowedUpdateService extends PaginatedScheduledService {
                     }
                 }
             }
+
+            private void loadModelDetails(LiveJasminModel model) {
+                try {
+                    String sessionId = liveJasmin.getHttpClient().getCookieJar().getCookie(HttpUrl.parse(liveJasmin.getBaseUrl()), "session").value();
+                    String detailsUrl = liveJasmin.getBaseUrl() + "/en/member/flash/get-performer-details/" + model.getName() + "?appletType=html5&noFlash=0&session=" + sessionId;
+                    Request request = new Request.Builder()
+                            .url(detailsUrl)
+                            .header(USER_AGENT, Config.getInstance().getSettings().httpUserAgent)
+                            .header(ACCEPT, "*/*")
+                            .header(ACCEPT_LANGUAGE, Locale.ENGLISH.getLanguage())
+                            .header(REFERER, liveJasmin.getBaseUrl() + "/en/member/chat-html5/" + model.getName())
+                            .build();
+                    try (Response response = liveJasmin.getHttpClient().execute(request)) {
+                        if (response.isSuccessful()) {
+                            JSONObject json = new JSONObject(response.body().string());
+                            if (json.optBoolean("success")) {
+                                JSONObject data = json.getJSONObject("data");
+                                model.setPreview(data.getString("profile_picture_url"));
+                            }
+                        }
+                    }
+                } catch(IOException e) {
+                    // details couldn't be loaded, but that doesn't matter
+                }
+            }
         };
     }
+
+    public void setShowOnline(boolean showOnline) {
+        this.showOnline = showOnline;
+    }
 }