diff --git a/assets/img/favori_add.png b/assets/img/favori_add.png
new file mode 100644
index 0000000000000000000000000000000000000000..f02f205a73bf82eaa22a74f72deaf0d00568e220
Binary files /dev/null and b/assets/img/favori_add.png differ
diff --git a/assets/img/favori_remove.png b/assets/img/favori_remove.png
new file mode 100644
index 0000000000000000000000000000000000000000..06b43589048636ea9ff8bab2dd43b0f598a8c2e2
Binary files /dev/null and b/assets/img/favori_remove.png differ
diff --git a/components/btn/Clipboard.vue b/components/btn/Clipboard.vue
index eb8c5f06a7145d3b127733689e08e70d69c2ff57..121b4f5e0a0361bc61182bb4b88a48e08ead3680 100644
--- a/components/btn/Clipboard.vue
+++ b/components/btn/Clipboard.vue
@@ -33,7 +33,7 @@ export default {
 			$("#btncopy").tooltip("show")
 			setTimeout(() => {
 				$("#btncopy").tooltip("hide")
-			}, 500)
+			}, 1000)
 		}
 	}
 }
diff --git a/components/member/Card.vue b/components/member/Card.vue
index 442ce2fbe43b7cd3c14316e4609602371d4b3d0c..10bae0633b529aec87e6fb7ef34b0c9f763bcda7 100644
--- a/components/member/Card.vue
+++ b/components/member/Card.vue
@@ -1,7 +1,15 @@
 <template>
 	<div class="card member">
+		<button
+			id="favori"
+			class="btn btn-light position-absolute"
+			:class="{
+				add: !isFavorite,
+				remove: isFavorite
+			}"
+			@click="toggleFavourite"></button>
 		<div class="card-body">
-			<h2 class="card-title text-center">
+			<h2 class="card-title text-center mb-4">
 				{{ hash.uid }}
 				<BadgeStatus :membre="hash" />
 			</h2>
@@ -121,13 +129,74 @@
 
 <script>
 export default {
+	data() {
+		return {
+			favourites: []
+		}
+	},
 	props: {
 		hash: Object
+	},
+	methods: {
+		toggleFavourite() {
+			let $this = this
+
+			$("#favori").tooltip({
+				title: function () {
+					return $this.isFavorite
+						? $this.$t("favoris.supprime")
+						: $this.$t("favoris.enregistre")
+				},
+				html: true,
+				trigger: "manual"
+			})
+
+			$("#favori").tooltip("show")
+			setTimeout(() => {
+				$("#favori").tooltip("hide")
+			}, 1000)
+
+			if (!this.isFavorite) {
+				this.favourites.push(this.hash.uid)
+			} else {
+				this.favourites.splice(this.favourites.indexOf(this.hash.uid), 1)
+			}
+
+			localStorage.favourites = JSON.stringify(this.favourites)
+		}
+	},
+	computed: {
+		isFavorite() {
+			this.favourites = localStorage.favourites
+				? JSON.parse(localStorage.favourites)
+				: []
+
+			return this.favourites.includes(this.hash.uid)
+		}
 	}
 }
 </script>
 
 <style lang="scss">
+#favori {
+	top: 1.25rem;
+	left: 1.25rem;
+	background-color: var(--light);
+	background-size: 75%;
+	background-repeat: no-repeat;
+	background-position: center;
+	width: 50px;
+	height: 50px;
+
+	&.add {
+		background-image: url("~/assets/img/favori_add.png");
+	}
+
+	&.remove {
+		background-image: url("~/assets/img/favori_remove.png");
+	}
+}
+
 .member {
 	.table {
 		text-align: center;
diff --git a/graphql/cache.js b/graphql/cache.js
index 21055e0225ac2552ebaeaf74e99473d9d76f5495..b8dff3ab0aa40ff1915392b50022bfd76b8cfe1a 100644
--- a/graphql/cache.js
+++ b/graphql/cache.js
@@ -1,21 +1,32 @@
-import { InMemoryCache, IntrospectionFragmentMatcher, defaultDataIdFromObject } from 'apollo-cache-inmemory'
-import introspectionQueryResultData from './fragmentTypes.json';
+import {
+	InMemoryCache,
+	IntrospectionFragmentMatcher,
+	defaultDataIdFromObject
+} from "apollo-cache-inmemory"
+import introspectionQueryResultData from "./fragmentTypes.json"
 
 const fragmentMatcher = new IntrospectionFragmentMatcher({
-    introspectionQueryResultData
+	introspectionQueryResultData
 })
 
 // Apparemment il faut utiliser la syntaxe Apollo v2
 export const cache = new InMemoryCache({
-    addTypename: false,
-    fragmentMatcher,
-    dataIdFromObject: object => {
-        switch (object.__typename) {
-            case 'Identity': return object.hash
-            case 'Event': return object.block.number
-            case 'EventId': return `${object.member.hash}:${object.inOut}`
-            case 'Forecast': return `${object.member.hash}:${object.date}:${object.after}:${object.proba}`
-            default: return defaultDataIdFromObject(object); // fall back to default handling
-        }
-    }
-})
\ No newline at end of file
+	addTypename: false,
+	fragmentMatcher,
+	dataIdFromObject: (object) => {
+		switch (object.__typename) {
+			case "Identity":
+				return object.hash
+			case "Event":
+				return object.block.number
+			case "EventId":
+				return `${object.member.hash}:${object.inOut}`
+			case "Forecast":
+				return `${object.member.hash}:${object.date}:${object.after}:${object.proba}`
+			case "GroupId":
+				return `${object.id.hash}`
+			default:
+				return defaultDataIdFromObject(object) // fall back to default handling
+		}
+	}
+})
diff --git a/graphql/queries.js b/graphql/queries.js
index 0df3c0f8e3365d1373da9e4e98b0fd42b28e2a96..5e0b8ddfc63a4ae0e271ab1b1bc48f2987f2f713 100644
--- a/graphql/queries.js
+++ b/graphql/queries.js
@@ -1,243 +1,208 @@
 import gql from "graphql-tag"
 
 // Pour la sidebar
-export const LAST_BLOCK = gql`query LastBlock{
-	countMax {
-    number
-    bct
-    utc0
-  }
-}`
+export const LAST_BLOCK = gql`
+	query LastBlock {
+		countMax {
+			number
+			bct
+			utc0
+		}
+	}
+`
 
 // Pour la page index
-export const LAST_EVENTS = gql`query LastEvents($start: Int64, $end: Int64) {
-  membersCount(start: $start, end: $end) {
-    idList {
-      __typename
-      member : id {
-        __typename
-        pubkey
-        uid
-        status
-        hash
-        limitDate
-        history {
-          __typename
-          in
-          block {
-            __typename
-            number
-          }
-        }
-        received_certifications {
-          __typename
-          limit
-        }
-      }
-      inOut
-    },
-    block {
-      __typename
-      number
-    }
-  }
-} `
-
-// Pour la page previsions/index
-export const PREVISIONS = gql`query GetDossiers {
-    now {
-      number
-      bct
-      __typename
-    }
-    parameter(name: sigQty) {
-      sigQty: value
-      __typename
-    }
-    wwFile(full: true) {
-      certifs_dossiers {
-        ... on MarkedDatedCertification {
-          datedCertification {
-            date
-            certification {
-              from {
-                uid
-                __typename
-              }
-              to {
-                uid
-                __typename
-              }
-              expires_on
-              __typename
-            }
-            __typename
-          }
-          __typename
-        }
-        ... on MarkedDossier {
-          dossier {
-            main_certifs
-            newcomer {
-              uid
-              lastApplication {
-                lastAppDate: bct
-                __typename
-              }
-              distance: distanceE {
-                value {
-                  ratio
-                  __typename
-                }
-                dist_ok
-                __typename
-              }
-              __typename
-            }
-            date
-            minDate
-            expires_on: limit
-            certifications {
-              date
-              certification {
-                from {
-                  uid
-                  quality {
-                    ratio
-                    __typename
-                  }
-                  __typename
-                }
-                expires_on
-                __typename
-              }
-              __typename
-            }
-            __typename
-          }
-          __typename
-        }
-      }
-      __typename
-    }
-  }`
+export const LAST_EVENTS = gql`
+	query LastEvents($start: Int64, $end: Int64) {
+		membersCount(start: $start, end: $end) {
+			idList {
+				__typename
+				member: id {
+					__typename
+					pubkey
+					uid
+					status
+					hash
+					limitDate
+					history {
+						__typename
+						in
+						block {
+							__typename
+							number
+						}
+					}
+					received_certifications {
+						__typename
+						limit
+					}
+				}
+				inOut
+			}
+			block {
+				__typename
+				number
+			}
+		}
+	}
+`
 
 // Pour la page previsions/newcomers
-export const NEWCOMERS = gql`query GetNewcomers{
-    wwResult {
-        __typename
-        permutations_nb
-        dossiers_nb
-        certifs_nb
-        forecastsByNames {
-            __typename
-            member : id {
-                __typename
-                pubkey
-                uid
-                status
-                hash
-                limitDate
-                received_certifications {
-                    __typename
-                    limit
-                }
-            }
-            date
-            after
-            proba
-        }
-    }
-} `
+export const NEWCOMERS = gql`
+	query GetNewcomers {
+		wwResult {
+			__typename
+			permutations_nb
+			dossiers_nb
+			certifs_nb
+			forecastsByNames {
+				__typename
+				member: id {
+					__typename
+					pubkey
+					uid
+					status
+					hash
+					limitDate
+					received_certifications {
+						__typename
+						limit
+					}
+				}
+				date
+				after
+				proba
+			}
+		}
+	}
+`
 
 // Pour la page membres/index
-export const SEARCH_MEMBERS = gql`query SearchMember($hint: String) {
-    idSearch(with: {hint: $hint}) {
-        __typename
-        ids {
-            __typename
-            pubkey
-            uid
-            status
-            hash
-            limitDate
-            received_certifications {
-                __typename
-                limit
-            }
-        }
-    }
-} `
+export const SEARCH_MEMBERS = gql`
+	query SearchMember($hint: String) {
+		idSearch(with: { hint: $hint }) {
+			__typename
+			ids {
+				__typename
+				pubkey
+				uid
+				status
+				hash
+				limitDate
+				received_certifications {
+					__typename
+					limit
+				}
+			}
+		}
+	}
+`
 
 // Pour la page membres/_hash
-export const SEARCH_MEMBER = gql`query SearchMemberWithHash($hash: Hash!) {
-    idFromHash(hash: $hash) {
-        ...attr
-        pubkey
-        isLeaving
-        sentry
-        membership_pending
-        limitDate
-        distanceE {
-          __typename
-          value {
-            __typename
-            ratio
-          }
-          dist_ok
-        }
-        distance {
-          __typename
-          value {
-            __typename
-            ratio
-          }
-          dist_ok
-        }
-        received_certifications {
-          __typename
-          certifications {
-            __typename
-            from {
-              ...attr
-            }
-            expires_on
-            pending
-          }
-        }
-        sent_certifications {
-          __typename
-          to {
-            ...attr
-          }
-          expires_on
-          pending
-        }
-    }
-}
-fragment attr on Identity {
-  __typename
-  uid
-  hash
-  status
-  minDate
-  minDatePassed
-  quality {
-    __typename
-    ratio
-  }
-  received_certifications {
-    __typename
-    limit
-  }
-}`
+export const SEARCH_MEMBER = gql`
+	query SearchMemberWithHash($hash: Hash!) {
+		idFromHash(hash: $hash) {
+			...attr
+			pubkey
+			isLeaving
+			sentry
+			membership_pending
+			limitDate
+			distanceE {
+				__typename
+				value {
+					__typename
+					ratio
+				}
+				dist_ok
+			}
+			distance {
+				__typename
+				value {
+					__typename
+					ratio
+				}
+				dist_ok
+			}
+			received_certifications {
+				__typename
+				certifications {
+					__typename
+					from {
+						...attr
+					}
+					expires_on
+					pending
+				}
+			}
+			sent_certifications {
+				__typename
+				to {
+					...attr
+				}
+				expires_on
+				pending
+			}
+		}
+	}
+	fragment attr on Identity {
+		__typename
+		uid
+		hash
+		status
+		minDate
+		minDatePassed
+		quality {
+			__typename
+			ratio
+		}
+		received_certifications {
+			__typename
+			limit
+		}
+	}
+`
 
 // Pour la page parametres
-export const PARAMS = gql`query getParams{
-  allParameters {
-    name
-    par_type
-    value
-    comment
-  }
-}`
\ No newline at end of file
+export const PARAMS = gql`
+	query getParams {
+		allParameters {
+			name
+			par_type
+			value
+			comment
+		}
+	}
+`
+// Pour la page favoris
+export const FAVORIS = gql`
+	query getFavoris($group: [String!]!) {
+		filterGroup(group: $group) {
+			__typename
+			selected {
+				__typename
+				id {
+					...attr
+				}
+			}
+			others {
+				__typename
+				id {
+					...attr
+				}
+			}
+		}
+	}
+	fragment attr on Identity {
+		__typename
+		pubkey
+		uid
+		status
+		hash
+		limitDate
+		received_certifications {
+			__typename
+			limit
+		}
+	}
+`
diff --git a/i18n/locales/en.json b/i18n/locales/en.json
index 3346c2a805d65d889cbd0f3716d00a5ef98ab5d2..fbfd6b4cae7818f9955a9ea97e1aaf7d8644ce25 100644
--- a/i18n/locales/en.json
+++ b/i18n/locales/en.json
@@ -62,6 +62,12 @@
 		"title": "Duniter"
 	},
 	"expire": "Expires",
+	"favoris": {
+		"enregistre": "Saved to favorites&nbsp;!",
+		"none": "You don't have any favorites yet",
+		"supprime": "Deleted from favourites&nbsp;!",
+		"title": "My favourites"
+	},
 	"futuremembers": "Future members",
 	"infos": "Informations",
 	"inout": "Entries and exits of the web of trust for the last 2 days",
diff --git a/i18n/locales/es.json b/i18n/locales/es.json
index 431d87eb55c7d5895f79f62568d1cd9d03fdb065..22e9c868d823c5b65cf896bc0677113e0ced26dd 100644
--- a/i18n/locales/es.json
+++ b/i18n/locales/es.json
@@ -62,6 +62,12 @@
 		"title": "Duniter"
 	},
 	"expire": "Expira el",
+	"favoris": {
+		"enregistre": "¡Guardado en favoritos!",
+		"none": "Aún no tienes favoritos",
+		"supprime": "¡Eliminado de favoritos!",
+		"title": "Mis favoritos"
+	},
 	"futuremembers": "Futuros miembros",
 	"infos": "Informaciones",
 	"inout": "Entradas y salidas de la red de confianza en los últimos 2 días",
diff --git a/i18n/locales/fr.json b/i18n/locales/fr.json
index c0a1b104cc81b803708451829ef28e6856b573c3..0407b24ba65a1b0545232d1d212df2048c49d72a 100644
--- a/i18n/locales/fr.json
+++ b/i18n/locales/fr.json
@@ -62,6 +62,12 @@
 		"title": "Duniter"
 	},
 	"expire": "Expire le",
+	"favoris": {
+		"enregistre": "Enregistré dans les favoris&nbsp;!",
+		"none": "Vous n'avez pas encore de favoris",
+		"supprime": "Supprimé des favoris&nbsp;!",
+		"title": "Mes favoris"
+	},
 	"futuremembers": "Futurs membres",
 	"infos": "Informations",
 	"inout": "Entrées et sorties de la toile de confiance des 2 derniers jours",
diff --git a/layouts/default.vue b/layouts/default.vue
index f3ee63e12571041daafe342b4b08f147b23e0e2b..651572ffc0ca15a236d8ca5dedb4809645c36ad2 100644
--- a/layouts/default.vue
+++ b/layouts/default.vue
@@ -14,7 +14,10 @@ export default {
 			menus: [
 				{
 					title: "wot.title",
-					items: [{ path: "/membres", title: "membres" }]
+					items: [
+						{ path: "/membres", title: "membres" },
+						{ path: "/favoris", title: "favoris.title" }
+					]
 				},
 				{
 					title: "previsions.title",
diff --git a/pages/favoris.vue b/pages/favoris.vue
new file mode 100644
index 0000000000000000000000000000000000000000..a17eb948f07221f9d59dc1a229390bb376a7d9ed
--- /dev/null
+++ b/pages/favoris.vue
@@ -0,0 +1,94 @@
+<template>
+	<main class="container">
+		<h2 class="text-center my-5 font-weight-light">
+			{{ $t("favoris.title") }}
+		</h2>
+
+		<NavigationLoader :isLoading="$apollo.queries.favoris.loading" />
+		<div class="row text-center">
+			<div class="col">
+				<transition name="fade">
+					<div class="alert alert-danger" v-if="error">{{ error }}</div>
+				</transition>
+				<transition name="fade">
+					<MemberList
+						:members="favoris"
+						v-if="favoris && favoris.length != 0" />
+				</transition>
+				<transition name="fade">
+					<div
+						class="alert alert-info"
+						v-if="!$apollo.queries.favoris.loading && favoris.length == 0">
+						{{ $t("favoris.none") }}
+					</div>
+				</transition>
+			</div>
+		</div>
+	</main>
+</template>
+
+<script>
+import { FAVORIS } from "@/graphql/queries.js"
+
+export default {
+	data() {
+		return {
+			breadcrumb: [
+				{
+					text: this.$t("accueil"),
+					to: "/"
+				},
+				{
+					text: this.$t("favoris.title"),
+					active: true
+				}
+			],
+			error: null
+		}
+	},
+	// local functions. You can use :
+	// {{ myFunction() }} in template if a value is returned
+	// - this.myFunction everywhere in the page but not in arrows functions
+	// - @event="myFunction" on Vue eventHandlers
+	// methods: {
+	//   myFunction() {
+
+	//   }
+	// },
+	// For computed values. Use {{ myComputedValue }} in the template
+	// computed: {
+	//   myComputedValue : function() {
+	//     return this.var * 3
+	//   }
+	// },
+	apollo: {
+		favoris: {
+			query: FAVORIS,
+			variables() {
+				return { group: JSON.parse(localStorage.favourites) }
+			},
+			update(data) {
+				let retour = []
+				for (let i = 0; i < data.filterGroup.selected.length; i++) {
+					retour[i] = data.filterGroup.selected[i].id
+				}
+
+				return retour
+			},
+			error(err) {
+				this.error = err.message
+			}
+		}
+	},
+	nuxtI18n: {
+		paths: {
+			fr: "/favoris",
+			en: "/favourites",
+			es: "/favoritos"
+		}
+	},
+	mounted() {
+		$nuxt.$emit("changeRoute", this.breadcrumb)
+	}
+}
+</script>