diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 55555ef68761fb4980cbebaad70284d496acc1c6..d9e817e76f8c4529d37bca4f59ae746c48be36fa 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -1,13 +1,9 @@
 variables:
   MAVEN_OPTS: "-Dmaven.repo.local=$CI_PROJECT_DIR/.m2/repository"
 
+# To use the registry, DOCKER_AUTH_CONFIG must be set
 image: registry.forgemia.inra.fr/agroclim/common/docker-projets-java:latest
 
-# hack to ignore failing runners
-# https://forgemia.inra.fr/adminforgemia/support/-/issues/216
-default:
-  tags: ["test"]
-
 stages:
     - build
     - test
diff --git a/sql/schema.tables.sql b/sql/schema.tables.sql
index 3df03ed88412159808abf3060ff9bb5a8e917418..85a7f2d37b9e00b9f6f62837cfb7a979fe4356a2 100644
--- a/sql/schema.tables.sql
+++ b/sql/schema.tables.sql
@@ -203,6 +203,16 @@ COMMENT ON COLUMN dailyvalue.computedvalue IS 'Value of the indicator.';
 COMMENT ON COLUMN dailyvalue.comparedvalue IS 'Value of the indicator compared to the normal.';
 CREATE INDEX IF NOT EXISTS "IX_dailyvalue" ON dailyvalue USING btree (date, cell);
 
+CREATE TABLE IF NOT EXISTS dailyvisit(
+    id SERIAL,
+    date DATE NOT NULL,
+    environment VARCHAR NOT NULL,
+    number INTEGER NOT NULL,
+    CONSTRAINT "PK_dailyvisit" PRIMARY KEY (id),
+    CONSTRAINT "UK_dailyvisit" UNIQUE (date, environment)
+);
+COMMENT ON TABLE dailyvisit IS 'Number of visits per day.';
+
 CREATE OR REPLACE VIEW v_i18n
 AS SELECT l.languagetag,
     i.i18nkey,
diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/dao/DailyVisitDao.java b/www-server/src/main/java/fr/agrometinfo/www/server/dao/DailyVisitDao.java
new file mode 100644
index 0000000000000000000000000000000000000000..f8709715009068f78b7b16193945536a6be63202
--- /dev/null
+++ b/www-server/src/main/java/fr/agrometinfo/www/server/dao/DailyVisitDao.java
@@ -0,0 +1,25 @@
+package fr.agrometinfo.www.server.dao;
+
+import java.util.List;
+
+import fr.agrometinfo.www.server.model.DailyVisit;
+
+/**
+ * DAO for dailyvisit table.
+ *
+ * @author Olivier Maury
+ */
+public interface DailyVisitDao {
+    /**
+     * @return all entities
+     */
+    List<DailyVisit> findAll();
+
+    /**
+     * Increment the daily value if exists or add a new row with 1 as total number
+     * of visits.
+     *
+     * @param environment code
+     */
+    void increment(String environment);
+}
diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/dao/DailyVisitDaoHibernate.java b/www-server/src/main/java/fr/agrometinfo/www/server/dao/DailyVisitDaoHibernate.java
new file mode 100644
index 0000000000000000000000000000000000000000..a24a802b55691e9b96ecbc1da318845dc959acc1
--- /dev/null
+++ b/www-server/src/main/java/fr/agrometinfo/www/server/dao/DailyVisitDaoHibernate.java
@@ -0,0 +1,51 @@
+package fr.agrometinfo.www.server.dao;
+
+import fr.agrometinfo.www.server.model.DailyVisit;
+import jakarta.enterprise.context.ApplicationScoped;
+import jakarta.transaction.Transactional;
+
+/**
+ * Hibernate implementation of {@link DailyVisit}.
+ *
+ * @author Olivier Maury
+ */
+@ApplicationScoped
+public class DailyVisitDaoHibernate extends DaoHibernate<DailyVisit> implements DailyVisitDao {
+    /**
+     * Statement to insert a new row.
+     */
+    private static final String INSERT_SQL = """
+            INSERT INTO dailyvisit (date, environment, number) VALUES (CURRENT_DATE, :environment, 1)
+            """;
+    /**
+     * Statement to increment.
+     */
+    private static final String UPDATE_SQL = """
+            UPDATE dailyvisit SET number=number+1 WHERE date=CURRENT_DATE and environment=:environment
+            """;
+
+    /**
+     * Constructor.
+     */
+    public DailyVisitDaoHibernate() {
+        super(DailyVisit.class);
+    }
+
+    @Transactional
+    @Override
+    public final void increment(final String environment) {
+        // INSERT INTO ... ON CONFLICT is not available in H2
+        // MERGE is available in PostgreSQL >= 14 and H2
+        doInJpaTransaction(em -> {
+            var query = em.createNativeQuery(UPDATE_SQL);
+            query.setParameter("environment", environment);
+            final int nb = query.executeUpdate();
+            if (nb == 0) {
+                query = em.createNativeQuery(INSERT_SQL);
+                query.setParameter("environment", environment);
+                query.executeUpdate();
+            }
+        });
+    }
+
+}
diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/dao/DaoHibernate.java b/www-server/src/main/java/fr/agrometinfo/www/server/dao/DaoHibernate.java
index 2545bae33f3ef449b846defe0643c2933f919865..b9b9c20ad5c038bd46df971558c3d2c943b7fedc 100644
--- a/www-server/src/main/java/fr/agrometinfo/www/server/dao/DaoHibernate.java
+++ b/www-server/src/main/java/fr/agrometinfo/www/server/dao/DaoHibernate.java
@@ -6,6 +6,7 @@ import java.sql.SQLException;
 import java.util.ArrayList;
 import java.util.List;
 import java.util.Map;
+import java.util.function.Consumer;
 
 import org.hibernate.engine.spi.SessionImplementor;
 
@@ -86,6 +87,19 @@ public abstract class DaoHibernate<T> {
         }
     }
 
+    /**
+     * Use a consumer to execute JPA operations in a transaction.
+     *
+     * @param consumer consumer with JPA operations
+     */
+    protected final void doInJpaTransaction(final Consumer<ScopedEntityManager> consumer) {
+        try (ScopedEntityManager em = getScopedEntityManager()) {
+            em.executeTransaction(() -> {
+                consumer.accept(em);
+            });
+        }
+    }
+
     /**
      * Find by primary key.
      *
diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/model/DailyVisit.java b/www-server/src/main/java/fr/agrometinfo/www/server/model/DailyVisit.java
new file mode 100644
index 0000000000000000000000000000000000000000..80b3a47aea2e0be6fc275319e0c0054fd9770083
--- /dev/null
+++ b/www-server/src/main/java/fr/agrometinfo/www/server/model/DailyVisit.java
@@ -0,0 +1,44 @@
+package fr.agrometinfo.www.server.model;
+
+import java.time.LocalDate;
+
+import jakarta.persistence.Column;
+import jakarta.persistence.Entity;
+import jakarta.persistence.GeneratedValue;
+import jakarta.persistence.GenerationType;
+import jakarta.persistence.Id;
+import jakarta.persistence.Table;
+import lombok.Data;
+
+/**
+ * Number of visits per day.
+ *
+ * @author Olivier Maury
+ */
+@Data
+@Entity
+@Table(name = "dailyvisit")
+public class DailyVisit {
+    /**
+     * PK.
+     */
+    @Id
+    @GeneratedValue(strategy = GenerationType.AUTO)
+    @Column(name = "id")
+    private long id;
+    /**
+     * Date.
+     */
+    @Column(name = "date", nullable = false)
+    private LocalDate date = LocalDate.now();
+    /**
+     * Environment code.
+     */
+    @Column(name = "environment")
+    private String environment;
+    /**
+     * Number of visits per day.
+     */
+    @Column(name = "number")
+    private Integer number;
+}
diff --git a/www-server/src/main/java/fr/agrometinfo/www/server/rs/ApplicationResource.java b/www-server/src/main/java/fr/agrometinfo/www/server/rs/ApplicationResource.java
index 9718829424c558c858f230a98db06e41e0b2f0ba..8a7b184e3ff956b1718537e2854a12b8a95c4c6e 100644
--- a/www-server/src/main/java/fr/agrometinfo/www/server/rs/ApplicationResource.java
+++ b/www-server/src/main/java/fr/agrometinfo/www/server/rs/ApplicationResource.java
@@ -5,7 +5,9 @@ import java.util.List;
 
 import fr.agrometinfo.www.server.AgroMetInfoConfiguration;
 import fr.agrometinfo.www.server.AgroMetInfoConfiguration.ConfigurationKey;
+import fr.agrometinfo.www.server.dao.DailyVisitDao;
 import fr.agrometinfo.www.server.exception.AgroMetInfoException;
+import fr.agrometinfo.www.server.model.DailyVisit;
 import fr.agrometinfo.www.server.service.MailService;
 import fr.agrometinfo.www.server.service.MailService.Mail;
 import fr.agrometinfo.www.server.util.AppVersion;
@@ -49,6 +51,12 @@ public class ApplicationResource implements ApplicationService {
     @Inject
     private AgroMetInfoConfiguration configuration;
 
+    /**
+     * DAO for {@link DailyVisit}.
+     */
+    @Inject
+    private DailyVisitDao dailyVisitDao;
+
     /**
      * Mail service.
      */
@@ -65,6 +73,8 @@ public class ApplicationResource implements ApplicationService {
     @Produces({MediaType.APPLICATION_JSON, MediaType.APPLICATION_XML})
     @Override
     public Date getApplicationDate() {
+        // this is the first call, so register the visit.
+        dailyVisitDao.increment(configuration.get(ConfigurationKey.ENVIRONMENT));
         return applicationDate;
     }
 
diff --git a/www-server/src/test/java/fr/agrometinfo/www/server/dao/DailyVisitDaoHibernateTest.java b/www-server/src/test/java/fr/agrometinfo/www/server/dao/DailyVisitDaoHibernateTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..b21a22ad62de6716ed996d8839a13a05e6f3a1a2
--- /dev/null
+++ b/www-server/src/test/java/fr/agrometinfo/www/server/dao/DailyVisitDaoHibernateTest.java
@@ -0,0 +1,39 @@
+package fr.agrometinfo.www.server.dao;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import org.junit.jupiter.api.Test;
+
+/**
+ * Test DailyVisitDao Hibernate implementation.
+ */
+class DailyVisitDaoHibernateTest {
+    /**
+     * DAO to test.
+     */
+    private final DailyVisitDao dao = new DailyVisitDaoHibernate();
+
+    @Test
+    void increment() {
+        final String environment = "test";
+
+        var actual = dao.findAll();
+        assertNotNull(actual, "List of daily visits must not be null!");
+        assertTrue(actual.isEmpty());
+
+        dao.increment(environment);
+        actual = dao.findAll();
+        assertNotNull(actual, "List of daily visits must not be null!");
+        assertFalse(actual.isEmpty());
+        assertEquals(1, actual.get(0).getNumber());
+
+        dao.increment(environment);
+        actual = dao.findAll();
+        assertNotNull(actual, "List of daily visits must not be null!");
+        assertFalse(actual.isEmpty());
+        assertEquals(2, actual.get(0).getNumber());
+    }
+}
diff --git a/www-server/src/test/resources/META-INF/persistence.xml b/www-server/src/test/resources/META-INF/persistence.xml
index 74353e4ccf49232e47ee293e7d1de0e1c3351f87..55e45d5f4a3201beda796c044bc38de54791015a 100644
--- a/www-server/src/test/resources/META-INF/persistence.xml
+++ b/www-server/src/test/resources/META-INF/persistence.xml
@@ -10,6 +10,7 @@
     <class>fr.agrometinfo.www.server.model.Cell</class>
     <class>fr.agrometinfo.www.server.model.ColorSequence</class>
     <class>fr.agrometinfo.www.server.model.DailyValue</class>
+    <class>fr.agrometinfo.www.server.model.DailyVisit</class>
     <class>fr.agrometinfo.www.server.model.Department</class>
     <class>fr.agrometinfo.www.server.model.Indicator</class>
     <class>fr.agrometinfo.www.server.model.Period</class>