diff --git a/README.md b/README.md
index 0c52f7dff3dcd85678d2067372c1b5da01241755..c92d710e2ad1985cb96f285aadd74e49b9c08e45 100644
--- a/README.md
+++ b/README.md
@@ -1,6 +1,6 @@
 # simplesamlphp-module-campusmultiauth
 
-Thanks to this module, you can use a saml:SP authentication source together with another authentication source providing basic auth (discovery service and login form are displayed on a single page). This module also supports [aarc_idp_hint](https://zenodo.org/record/4596667/files/AARC-G061-A_specification_for_IdP_hinting.pdf), so you can even skip the login page and be redirected to the targeted identity provider.
+Thanks to this module, you can use a saml:SP authentication source together with another authentication source providing basic auth (discovery service and login form are displayed on a single page).
 
 ## Theme configuration
 
@@ -83,6 +83,8 @@ This component represents a form with username and password. It can be used only
 
 `password_placeholder` - this is displayed as a placeholder in the input for the password. If you want to add localization, you can write the value as a map with language codes as keys and localized strings as values. If current language is not found in keys, the **_first one_** is used instead. If not set at all, it displays a default value.
 
+`entityid` - entityid of the identity provider. Needed for idp hinting.
+
 `priority` - can be set to `primary`, default value is `secondary`. It should be primary if you want users to use this component if they are able to.
 
 `end_col` - on a desktop, components are divided to two columns. If you want this component to be the last one in the first column, set this option to `true`.
@@ -131,6 +133,18 @@ Each identity is a map with the following possible options:
 
 `background_color` - background around the logo. Defined as a [CSS color value](https://developer.mozilla.org/en-US/docs/Web/CSS/color_value).
 
+## Hinting
+
+To help the user choose the right institution to log in, this module supports following standards:
+
+### [aarc_idp_hint](https://zenodo.org/record/4596667/files/AARC-G061-A_specification_for_IdP_hinting.pdf)
+
+A service provider can choose which identity provider should user use, he/she then skips the login page and is redirected to the targeted identity provider.
+
+### [idphint](https://aarc-project.eu/wp-content/uploads/2019/04/AARC-G049-A_specification_for_IdP_hinting-v6.pdf)
+
+A service provider can choose which identity provider(s) should user use. If there is only one option, the user is redirected directly to the identity provider. Otherwise, user chooses from identity providers sent in idphint parameter.
+
 ## Deployment
 
 The easiest way is to use [docker-campusidp](https://github.com/cesnet/docker-campusidp), which includes this module together with SimpleSAMLphp and PHP-FPM.
diff --git a/config-templates/module_campusmultiauth.php b/config-templates/module_campusmultiauth.php
index e9f64c2f718a540ea002826bbaad7a50b60b5c0e..0d5daf352983220c898f5291056beeb27b656abc 100644
--- a/config-templates/module_campusmultiauth.php
+++ b/config-templates/module_campusmultiauth.php
@@ -28,6 +28,7 @@ $config = [
                 'cs' => 'Heslo',
                 'en' => 'Password',
             ],
+            'entityid' => 'https://idp2.ics.muni.cz/idp/shibboleth',
         ],
         [
             'name' => 'searchbox',
diff --git a/lib/Auth/Source/Campusidp.php b/lib/Auth/Source/Campusidp.php
index 4d249a074ceeb17994df212ddcf71c4d46a7646e..8a5e5d1baa685f0a59bab7b0c6915d6e4247fcd6 100644
--- a/lib/Auth/Source/Campusidp.php
+++ b/lib/Auth/Source/Campusidp.php
@@ -15,6 +15,7 @@ use SimpleSAML\Module;
 use SimpleSAML\Module\core\Auth\UserPassBase;
 use SimpleSAML\Session;
 use SimpleSAML\Utils;
+use Transliterator;
 
 class Campusidp extends Source
 {
@@ -38,6 +39,8 @@ class Campusidp extends Source
 
     public const COOKIE_PASSWORD = 'password';
 
+    public const IDP_HINT_BUTTONS_LIMIT = 5;
+
     private $sources;
 
     private $userPassSourceName;
@@ -231,6 +234,157 @@ class Campusidp extends Source
         return false;
     }
 
+    public static function findSearchboxesToDisplay($hintedIdps, $config)
+    {
+        $result = [];
+
+        for ($i = 0; $i < count($config['components']); $i++) {
+            if ($config['components'][$i]['name'] === 'searchbox') {
+                $ch = curl_init();
+
+                curl_setopt(
+                    $ch,
+                    CURLOPT_URL,
+                    Module::getModuleURL(
+                        'campusmultiauth/idpSearch.php?idphint=' . json_encode(
+                            $hintedIdps
+                        ) . '&skipMatching=true' . '&index=' . $i
+                    )
+                );
+                curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+
+                $idps = json_decode(curl_exec($ch));
+
+                curl_close($ch);
+
+                if (!empty($idps->items)) {
+                    $result[] = $i;
+                }
+            }
+        }
+
+        return $result;
+    }
+
+    public static function findIndividualIdentitiesToDisplay($hintedIdps, $config)
+    {
+        $result = [];
+
+        for ($i = 0; $i < count($config['components']); $i++) {
+            if ($config['components'][$i]['name'] === 'individual_identities') {
+                $componentToDisplay = false;
+
+                foreach ($config['components'][$i]['identities'] as $identity) {
+                    if (in_array($identity['upstream_idp'], $hintedIdps, true)) {
+                        $componentToDisplay = true;
+                        break;
+                    }
+                }
+
+                if ($componentToDisplay) {
+                    $result[] = $i;
+                }
+            }
+        }
+
+        return $result;
+    }
+
+    public static function getOrPositions($searchboxesToDisplay, $individualIdentitiesToDisplay, $idphint, $config)
+    {
+        $result = [];
+
+        $componentsToDisplay = [];
+        $endColComponent = -1;
+
+        for ($i = 0; $i < count($config['components']); $i++) {
+            if ($config['components'][$i]['name'] === 'local_login' && in_array(
+                $config['components'][$i]['entityid'],
+                $idphint,
+                true
+            )) {
+                $componentsToDisplay[] = $i;
+            }
+
+            if (!empty($config['components'][$i]['end_col']) && $config['components'][$i]['end_col'] === true) {
+                $endColComponent = $i;
+            }
+        }
+
+        $componentsToDisplay = array_merge($componentsToDisplay, $searchboxesToDisplay, $individualIdentitiesToDisplay);
+
+        foreach ($componentsToDisplay as $index1) {
+            if ($index1 <= $endColComponent) {
+                foreach ($componentsToDisplay as $index2) {
+                    if ($index1 < $index2 && $index2 <= $endColComponent) {
+                        $result[] = $index1;
+                        break;
+                    }
+                }
+            } else {
+                foreach ($componentsToDisplay as $index2) {
+                    if ($index1 < $index2) {
+                        $result[] = $index1;
+                        break;
+                    }
+                }
+            }
+        }
+
+        return $result;
+    }
+
+    public static function getIdpsMatchedBySearchTerm($metadata, $searchTerm)
+    {
+        $filteredMetadata = [];
+
+        $transliterator = Transliterator::createFromRules(
+            ':: Any-Latin; :: Latin-ASCII; :: NFD; :: [:Nonspacing Mark:] Remove; :: Lower(); :: NFC;',
+            Transliterator::FORWARD
+        );
+
+        foreach ($metadata as $entityid => $idpentry) {
+            if (!empty($idpentry['name']) && is_array($idpentry['name'])) {
+                foreach ($idpentry['name'] as $key => $value) {
+                    if (str_contains(
+                        $transliterator->transliterate($value),
+                        $transliterator->transliterate($searchTerm)
+                    )) {
+                        $filteredMetadata[$entityid] = $idpentry;
+                        break;
+                    }
+                }
+            }
+
+            if (!in_array($idpentry, $filteredMetadata, true) && !empty($idpentry['description']) && is_array(
+                $idpentry['description']
+            )) {
+                foreach ($idpentry['description'] as $key => $value) {
+                    if (str_contains(
+                        $transliterator->transliterate($value),
+                        $transliterator->transliterate($searchTerm)
+                    )) {
+                        $filteredMetadata[$entityid] = $idpentry;
+                        break;
+                    }
+                }
+            }
+
+            if (!in_array($idpentry, $filteredMetadata, true) && !empty($idpentry['url']) && is_array(
+                $idpentry['url']
+            )) {
+                foreach ($idpentry['url'] as $key => $value) {
+                    if (str_contains(strtolower($value), strtolower($searchTerm))) {
+                        $filteredMetadata[$entityid] = $idpentry;
+                        break;
+                    }
+                }
+            }
+        }
+
+        return $filteredMetadata;
+    }
+
     public function logout(&$state)
     {
         assert(is_array($state));
diff --git a/templates/includes/individual-identities.twig b/templates/includes/individual-identities.twig
index 1ae23a1152b567487a59101adee5e2c76f9d5a17..3f1fc6eb2e522a9b872e060e850987cfa8148198 100644
--- a/templates/includes/individual-identities.twig
+++ b/templates/includes/individual-identities.twig
@@ -16,18 +16,22 @@
         {% endif %}
     </h4>
 
+    {% set index = 0 %}
     {% for idp in configuration.identities %}
-        <div class="{% if muni_jvs %}margin-bottom-12{% endif %}{% if loop.index0 >= configuration.number_shown %} idp-hidden d-none vhide{% endif %}">
-            <button class="btn-individual-identity btn {% if muni_jvs %}btn-primary btn-border color-{{ configuration.priority }} hover-none-{{ configuration.priority }}{% else %}btn-light shadow-sm {% if configuration.priority == 'primary' %}border-dark text-dark{% else %}border-muted text-muted{% endif %} border-2{% endif %}" type="submit" name="idpentityid" value="{{ idp.upstream_idp }}">
-                {% if muni_jvs %}<span class="no-uppercase color-{{ configuration.priority }} individual-identity-span-wrap">{% endif %}
-                    <img class="individual-identity-logo{% if not muni_jvs %} border-end border-2 border-{% if configuration.priority == 'primary' %}dark{% else %}muted{% endif %}{% endif %}" {% if idp.background_color is defined %}style="background-color: {{ idp.background_color }}"{% endif %} src="{{ idp.logo }}" alt=""/>
-                    <span class="idp-text">{{ '{campusmultiauth:sign_in_with}'|trans }}{{ " " }}{% if attribute(idp.name, currentLanguage) is defined %}{{ attribute(idp.name, currentLanguage) }}
-                        {% elseif idp.name is defined and idp.name is iterable and idp.name is not empty %}{{ idp.name | first }}
-                        {% else %}{{ idp.name }}
-                        {% endif %}</span>
-                {% if muni_jvs %}</span>{% endif %}
-            </button>
-        </div>
+        {% if idphint is not defined or idp.upstream_idp in idphint %}
+            <div class="{% if muni_jvs %}margin-bottom-12{% endif %}{% if index >= configuration.number_shown %} idp-hidden d-none vhide{% endif %}">
+                <button class="btn-individual-identity btn {% if muni_jvs %}btn-primary btn-border color-{{ configuration.priority }} hover-none-{{ configuration.priority }}{% else %}btn-light shadow-sm {% if configuration.priority == 'primary' %}border-dark text-dark{% else %}border-muted text-muted{% endif %} border-2{% endif %}" type="submit" name="idpentityid" value="{{ idp.upstream_idp }}">
+                    {% if muni_jvs %}<span class="no-uppercase color-{{ configuration.priority }} individual-identity-span-wrap">{% endif %}
+                        <img class="individual-identity-logo img-searchbox{% if not muni_jvs %} border-end border-2 border-{% if configuration.priority == 'primary' %}dark{% else %}muted{% endif %}{% endif %}" {% if idp.background_color is defined %}style="background-color: {{ idp.background_color }}"{% endif %} src="{{ idp.logo }}" alt=""/>
+                        <span class="idp-text">{{ '{campusmultiauth:sign_in_with}'|trans }}{{ " " }}{% if attribute(idp.name, currentLanguage) is defined %}{{ attribute(idp.name, currentLanguage) }}
+                            {% elseif idp.name is defined and idp.name is iterable and idp.name is not empty %}{{ idp.name | first }}
+                            {% else %}{{ idp.name }}
+                            {% endif %}</span>
+                    {% if muni_jvs %}</span>{% endif %}
+                </button>
+            </div>
+            {% set index = index + 1 %}
+        {% endif %}
     {% endfor %}
 
     <input type="hidden" name="authstate" value="{{ authstate }}" />
diff --git a/templates/selectsource.twig b/templates/selectsource.twig
index 4dea312e3a9aab5e950a6b104d9b77a849555158..a8a5c35c49bf8271413eab974627264faade466d 100644
--- a/templates/selectsource.twig
+++ b/templates/selectsource.twig
@@ -18,6 +18,9 @@
     {{ parent() }}
     <script src="/{{baseurlpath}}module.php/campusmultiauth/resources/jquery-3.6.0.min.js"></script>
     <script src="/{{baseurlpath}}module.php/campusmultiauth/resources/selectize/js/standalone/selectize.min.js"></script>
+
+    <meta name="idphint" value="{% if idphint is defined %}{{ idphint | json_encode | raw }}{% endif %}">
+
     <script src="/{{baseurlpath}}module.php/campusmultiauth/resources/campus-idp.js"></script>
 {% endblock %}
 
@@ -31,32 +34,34 @@
                 {% block content %}
                     <div class="{% if muni_jvs %}grid{% else %}row{% endif %}">
                         <div class="{% if muni_jvs %}grid__cell size--m--2-4 first-col{% else %}col-md-6{% endif %} wrap-col">
+                            {% if hint_component_config is defined and hint_component_config.name == 'individual_identities' %}
+                                {% include '@campusmultiauth/includes/individual-identities.twig' with {'configuration': hint_component_config, 'component_index': 0} %}
+                            {% else %}
+                                {% for component_configuration in wayf_config.components %}
+                                    {% if component_configuration.name == 'local_login' and (idphint is not defined or component_configuration.entityid in idphint) %}
+                                        {% include '@campusmultiauth/includes/local-login.twig' with {'configuration': component_configuration} %}
+                                    {% elseif component_configuration.name == 'individual_identities' and (individual_identities_to_display is not defined or loop.index0 in individual_identities_to_display) %}
+                                        {% include '@campusmultiauth/includes/individual-identities.twig' with {'configuration': component_configuration, 'component_index': loop.index0} %}
+                                    {% elseif component_configuration.name == 'searchbox' and (searchboxes_to_display is not defined or loop.index0 in searchboxes_to_display) %}
+                                        {% include '@campusmultiauth/includes/searchbox.twig' with {'configuration': component_configuration, 'component_index': loop.index0} %}
+                                    {% endif %}
 
-                        {% for component_configuration in wayf_config.components %}
-                            {% if component_configuration.name == 'local_login' %}
-                                {% include '@campusmultiauth/includes/local-login.twig' with {'configuration': component_configuration} %}
-                            {% elseif component_configuration.name == 'individual_identities' %}
-                                {% include '@campusmultiauth/includes/individual-identities.twig' with {'configuration': component_configuration, 'component_index': loop.index0} %}
-                            {% elseif component_configuration.name == 'searchbox' %}
-                                {% include '@campusmultiauth/includes/searchbox.twig' with {'configuration': component_configuration, 'component_index': loop.index0} %}
-                            {% endif %}
-
-                            {% if component_configuration.end_col is defined and component_configuration.end_col %}
-                                </div>
-                                <div class="{% if muni_jvs %}grid__cell size--m--2-4{% else %}col-md-6{% endif %} wrap-col">
-                            {% endif %}
+                                    {% if component_configuration.end_col is defined and component_configuration.end_col %}
+                                        </div>
+                                        <div class="{% if muni_jvs %}grid__cell size--m--2-4{% else %}col-md-6{% endif %} wrap-col">
+                                    {% endif %}
 
-                            {% if not loop.last and (component_configuration.end_col is not defined or component_configuration.end_col != true) %}
-                                <div class="hrline color-secondary">
-                                    <span{% if not muni_jvs %} class="bg-light"{% endif %}>{{ '{campusmultiauth:or}'|trans }}</span>
-                                </div>
-                            {% elseif not loop.last and (component_configuration.end_col is defined and component_configuration.end_col == true) %}
-                                <div class="hrline last-col-component color-secondary">
-                                    <span{% if not muni_jvs %} class="bg-light"{% endif %}>{{ '{campusmultiauth:or}'|trans }}</span>
-                                </div>
+                                    {% if not loop.last and (component_configuration.end_col is not defined or component_configuration.end_col != true) and (or_positions is not defined or loop.index0 in or_positions) %}
+                                        <div class="hrline color-secondary">
+                                            <span{% if not muni_jvs %} class="bg-light"{% endif %}>{{ '{campusmultiauth:or}'|trans }}</span>
+                                        </div>
+                                    {% elseif not loop.last and (component_configuration.end_col is defined and component_configuration.end_col == true) %}
+                                        <div class="hrline last-col-component color-secondary">
+                                            <span{% if not muni_jvs %} class="bg-light"{% endif %}>{{ '{campusmultiauth:or}'|trans }}</span>
+                                        </div>
+                                    {% endif %}
+                                {% endfor %}
                             {% endif %}
-                        {% endfor %}
-
                         </div>
                     </div>
                 {% endblock %}
diff --git a/www/idpSearch.php b/www/idpSearch.php
index 45ac19fd378acf2bdac52ab956dcd4367fc90c1b..f3e873238c3e77d695f42e8ea61a255bdab8c1c5 100644
--- a/www/idpSearch.php
+++ b/www/idpSearch.php
@@ -8,118 +8,103 @@ use SimpleSAML\Module\campusmultiauth\Auth\Source\Campusidp;
 
 header('Content-type: application/json');
 
-$index = $_GET['index'];
-
-$config = Configuration::getConfig('module_campusmultiauth.php')->toArray();
-$searchBox = $config['components'][$index];
+$language = $_GET['language'] ?? 'en';
 
 $metadataStorageHandler = MetaDataStorageHandler::getMetadataHandler();
 $metadata = $metadataStorageHandler->getList();
 
-$searchTerm = $_GET['q'];
-$transliterator = Transliterator::createFromRules(
-    ':: Any-Latin; :: Latin-ASCII; :: NFD; :: [:Nonspacing Mark:] Remove; :: Lower(); :: NFC;',
-    Transliterator::FORWARD
-);
+if (!empty($_GET['idphint']) && !isset($_GET['index'])) {
+    $filteredData = array_intersect_key($metadata, array_flip(json_decode($_GET['idphint'])));
+} else {
+    $index = $_GET['index'];
+    $searchTerm = $_GET['q'] ?? '';
+    $skipMatching = $_GET['skipMatching'] ?? false;
 
-if (
-    !empty($searchBox['include']['upstream_idps']) ||
-    !empty($searchBox['include']['tags']) ||
-    !empty($searchBox['include']['registration_authorities'])
-) {
-    $filteredMetadata = [];
 
-    foreach ($metadata as $entityid => $idpentry) {
-        if (!empty($searchBox['include']['tags'])) {
-            foreach ($searchBox['include']['tags'] as $tag) {
-                if ($tag === $idpentry['tag']) {
-                    $filteredMetadata[$entityid] = $idpentry;
-                    break;
-                }
-            }
+    $config = Configuration::getConfig('module_campusmultiauth.php')->toArray();
+    $searchBox = $config['components'][$index];
+
+    if (!empty($_GET['idphint'])) {
+        $idphint = $_GET['idphint'];
+        if (!is_array($idphint)) {
+            $idphint = json_decode($idphint);
         }
 
-        if (!empty($searchBox['include']['registration_authorities']) && empty($filteredMetadata[$entityid])) {
-            foreach ($searchBox['include']['registration_authorities'] as $registrationAuthority) {
-                if (!empty($idpentry['RegistrationInfo']['registrationAuthority']) && $idpentry['RegistrationInfo']['registrationAuthority'] === $registrationAuthority) {
-                    $filteredMetadata[$entityid] = $idpentry;
-                    break;
+        $metadata = array_intersect_key($metadata, array_flip($idphint));
+    }
+
+    if (
+        !empty($searchBox['include']['upstream_idps']) ||
+        !empty($searchBox['include']['tags']) ||
+        !empty($searchBox['include']['registration_authorities'])
+    ) {
+        $filteredMetadata = [];
+
+        foreach ($metadata as $entityid => $idpentry) {
+            if (!empty($searchBox['include']['tags'])) {
+                foreach ($searchBox['include']['tags'] as $tag) {
+                    if ($tag === $idpentry['tag']) {
+                        $filteredMetadata[$entityid] = $idpentry;
+                        break;
+                    }
                 }
             }
-        }
 
-        if (!empty($searchBox['include']['upstream_idps']) && empty($filteredMetadata[$entityid])) {
-            foreach ($searchBox['include']['upstream_idps'] as $upstreamIdp) {
-                if ($upstreamIdp === $entityid) {
-                    $filteredMetadata[$entityid] = $idpentry;
-                    break;
+            if (!empty($searchBox['include']['registration_authorities']) && empty($filteredMetadata[$entityid])) {
+                foreach ($searchBox['include']['registration_authorities'] as $registrationAuthority) {
+                    if (!empty($idpentry['RegistrationInfo']['registrationAuthority']) && $idpentry['RegistrationInfo']['registrationAuthority'] === $registrationAuthority) {
+                        $filteredMetadata[$entityid] = $idpentry;
+                        break;
+                    }
                 }
             }
-        }
-    }
 
-    $metadata = $filteredMetadata;
-}
-
-foreach ($metadata as $entityid => $idpentry) {
-    if (!empty($searchBox['exclude']['tags'])) {
-        foreach ($searchBox['exclude']['tags'] as $tag) {
-            if ($tag === $idpentry['tag']) {
-                unset($metadata[$entityid]);
-                break;
+            if (!empty($searchBox['include']['upstream_idps']) && empty($filteredMetadata[$entityid])) {
+                foreach ($searchBox['include']['upstream_idps'] as $upstreamIdp) {
+                    if ($upstreamIdp === $entityid) {
+                        $filteredMetadata[$entityid] = $idpentry;
+                        break;
+                    }
+                }
             }
         }
-    }
 
-    if (!empty($searchBox['exclude']['registration_authorities']) && !empty($metadata[$entityid])) {
-        foreach ($searchBox['exclude']['registration_authorities'] as $registrationAuthority) {
-            if ($registrationAuthority === $idpentry['RegistrationInfo']['registrationAuthority']) {
-                unset($metadata[$entityid]);
-                break;
-            }
-        }
+        $metadata = $filteredMetadata;
     }
 
-    if (!empty($searchBox['exclude']['upstream_idps']) && !empty($metadata[$entityid])) {
-        foreach ($searchBox['exclude']['upstream_idps'] as $upstreamIdp) {
-            if ($upstreamIdp === $entityid) {
-                unset($metadata[$entityid]);
-                break;
+    foreach ($metadata as $entityid => $idpentry) {
+        if (!empty($searchBox['exclude']['tags'])) {
+            foreach ($searchBox['exclude']['tags'] as $tag) {
+                if ($tag === $idpentry['tag']) {
+                    unset($metadata[$entityid]);
+                    break;
+                }
             }
         }
-    }
-}
-
-$filteredData = [];
 
-foreach ($metadata as $entityid => $idpentry) {
-    if (!empty($idpentry['name']) && is_array($idpentry['name'])) {
-        foreach ($idpentry['name'] as $key => $value) {
-            if (str_contains($transliterator->transliterate($value), $transliterator->transliterate($searchTerm))) {
-                $filteredData[$entityid] = $idpentry;
-                break;
+        if (!empty($searchBox['exclude']['registration_authorities']) && !empty($metadata[$entityid])) {
+            foreach ($searchBox['exclude']['registration_authorities'] as $registrationAuthority) {
+                if ($registrationAuthority === $idpentry['RegistrationInfo']['registrationAuthority']) {
+                    unset($metadata[$entityid]);
+                    break;
+                }
             }
         }
-    }
 
-    if (!in_array($idpentry, $filteredData, true) && !empty($idpentry['description']) && is_array(
-        $idpentry['description']
-    )) {
-        foreach ($idpentry['description'] as $key => $value) {
-            if (str_contains($transliterator->transliterate($value), $transliterator->transliterate($searchTerm))) {
-                $filteredData[$entityid] = $idpentry;
-                break;
+        if (!empty($searchBox['exclude']['upstream_idps']) && !empty($metadata[$entityid])) {
+            foreach ($searchBox['exclude']['upstream_idps'] as $upstreamIdp) {
+                if ($upstreamIdp === $entityid) {
+                    unset($metadata[$entityid]);
+                    break;
+                }
             }
         }
     }
 
-    if (!in_array($idpentry, $filteredData, true) && !empty($idpentry['url']) && is_array($idpentry['url'])) {
-        foreach ($idpentry['url'] as $key => $value) {
-            if (str_contains(strtolower($value), strtolower($searchTerm))) {
-                $filteredData[$entityid] = $idpentry;
-                break;
-            }
-        }
+    if ($skipMatching) {
+        $filteredData = $metadata;
+    } else {
+        $filteredData = Campusidp::getIdpsMatchedBySearchTerm($metadata, $searchTerm);
     }
 }
 
@@ -129,8 +114,8 @@ foreach ($filteredData as $entityid => $idpentry) {
     $item['idpentityid'] = $entityid;
     $item['image'] = $searchBox['logos'][$entityid] ?? Campusidp::getMostSquareLikeImg($idpentry);
 
-    if (!empty($idpentry['name'][$_GET['language']])) {
-        $item['text'] = $idpentry['name'][$_GET['language']];
+    if (!empty($idpentry['name'][$language])) {
+        $item['text'] = $idpentry['name'][$language];
     } elseif (!empty($idpentry['name']['en'])) {
         $item['text'] = $idpentry['name']['en'];
     } elseif (reset($idpentry['name'])) {
diff --git a/www/resources/campus-idp.js b/www/resources/campus-idp.js
index 365b4543c809d9a50089874438369abc417e6f55..ff107946d8d1f1c68a4293b7428babdb290d92eb 100644
--- a/www/resources/campus-idp.js
+++ b/www/resources/campus-idp.js
@@ -77,6 +77,7 @@ function selectizeLoad(query, callback) {
 		data: {
 			q: query,
 			index: this.settings.myIndex,
+			idphint: this.settings.idphint,
 			language: document.documentElement.getAttribute("lang"),
 			page_limit: 10,
 		},
@@ -167,6 +168,7 @@ document.addEventListener("DOMContentLoaded", function () {
 			create: false,
 			maxItems: 1,
 			myIndex: index,
+			idphint: JSON.parse(document.querySelector('meta[name="idphint"]').content),
 			loadThrottle: 250,
 			placeholder: placeholderTexts[index] ?? defaultPlaceholder,
 			render: {
diff --git a/www/selectsource.php b/www/selectsource.php
index 008cecc5286bbd2f8b94c87939a46184f5f8f7a6..7dd0939da7da67b7e3586764312ef5ab39d517b5 100644
--- a/www/selectsource.php
+++ b/www/selectsource.php
@@ -34,9 +34,43 @@ if (array_key_exists('aarc_idp_hint', $state)) {
 
 if (array_key_exists('idphint', $state)) {
     $parts = explode(',', $state['idphint']);
+
     if (count($parts) === 1) {
         $state['saml:idp'] = urldecode($parts[0]);
         Campusidp::delegateAuthentication($state[Campusidp::SP_SOURCE_NAME], $state);
+    } else {
+        $idphint = [];
+        foreach ($parts as $part) {
+            $idphint[] = urldecode($part);
+        }
+
+        if (count($idphint) <= Campusidp::IDP_HINT_BUTTONS_LIMIT) {
+            $ch = curl_init();
+
+            curl_setopt(
+                $ch,
+                CURLOPT_URL,
+                Module::getModuleURL('campusmultiauth/idpSearch.php?idphint=' . json_encode($idphint))
+            );
+            curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+
+            $idpsAsConfigItems = json_decode(curl_exec($ch));
+            curl_close($ch);
+
+            $hintComponentConfig = [];
+            $hintComponentConfig['name'] = 'individual_identities';
+            $hintComponentConfig['priority'] = 'primary';
+            $hintComponentConfig['title'] = '';
+            $hintComponentConfig['number_shown'] = Campusidp::IDP_HINT_BUTTONS_LIMIT;
+
+            for ($i = 0; $i < count($idpsAsConfigItems->items); $i++) {
+                $hintComponentConfig['identities'][$i] = [
+                    'name' => $idpsAsConfigItems->items[$i]->text,
+                    'logo' => $idpsAsConfigItems->items[$i]->image,
+                    'upstream_idp' => $idpsAsConfigItems->items[$i]->idpentityid,
+                ];
+            }
+        }
     }
 }
 
@@ -141,6 +175,27 @@ $t->data['user_pass_source_name'] = $state[Campusidp::USER_PASS_SOURCE_NAME];
 $t->data['sp_source_name'] = $state[Campusidp::SP_SOURCE_NAME];
 $t->data['cookie_username'] = Campusidp::getCookie(Campusidp::COOKIE_USERNAME);
 $t->data['cookie_password'] = Campusidp::getCookie(Campusidp::COOKIE_PASSWORD);
+
+if (!empty($idphint)) {
+    $t->data['idphint'] = $idphint;
+
+    if (empty($hintComponentConfig)) {
+        $searchboxesToDisplay = Campusidp::findSearchboxesToDisplay($idphint, $wayfConfig);
+        $individualIdentitiesToDisplay = Campusidp::findIndividualIdentitiesToDisplay($idphint, $wayfConfig);
+
+        $t->data['searchboxes_to_display'] = $searchboxesToDisplay;
+        $t->data['individual_identities_to_display'] = $individualIdentitiesToDisplay;
+        $t->data['or_positions'] = Campusidp::getOrPositions(
+            $searchboxesToDisplay,
+            $individualIdentitiesToDisplay,
+            $idphint,
+            $wayfConfig
+        );
+    } else {
+        $t->data['hint_component_config'] = $hintComponentConfig;
+    }
+}
+
 $t->data['searchbox_indexes'] = json_encode(array_values(array_filter(array_map(function ($config, $index) {
     return $config['name'] === 'searchbox' ? $index : null;
 }, $wayfConfig['components'], array_keys($wayfConfig['components'])), function ($a) {