diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 218e7df5cf119b224c1b04e2720f3d14471d758d..9b24982b5f34ec8ef6f323698eb370962e6c691a 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -263,6 +263,7 @@ NSHM Web Tests:
   script:
     - CI_RUNNER_MEMORY="$(awk '/MemTotal/ {printf( "%d\n", $2 / 1024 / 1024 * .90 )}' /proc/meminfo)g"
     - export CI_RUNNER_MEMORY
+    - ./gradlew generate${NSHM} --info
     - ./gradlew test${NSHM} --info
     - cat ${JACOCO_HTML_DIR}/index.html
   stage: test
diff --git a/gradle/nshm.gradle b/gradle/nshm.gradle
index 2d4bb0440bb965cf0d31c833bfea013ad8b5dee8..d4bce26cdb9d159e07625094247fc994b689a848 100644
--- a/gradle/nshm.gradle
+++ b/gradle/nshm.gradle
@@ -100,6 +100,20 @@ task generateAlaska2023(type: JavaExec) {
   main = "gov.usgs.earthquake.nshmp.model.GenerateActual"
 }
 
+// Generate Alaska 2023 for CI
+task generateWebAlaska2023(type: JavaExec) {
+  description = "Generate alaska-2023 acutal for CI/CD"
+  classpath = sourceSets.test.runtimeClasspath
+
+  doFirst {
+    downloadNshm(findNshm("nshm-alaska", 2023))
+  }
+
+  jvmArgs("-DNSHM=nshm-alaska-2023")
+
+  main = "gov.usgs.earthquake.nshmp.model.GenerateWebActual"
+}
+
 
 // Generate CONUS 2018 for CI
 task generateConus2018(type: JavaExec) {
diff --git a/src/test/java/gov/usgs/earthquake/nshmp/model/GenerateWebActual.java b/src/test/java/gov/usgs/earthquake/nshmp/model/GenerateWebActual.java
new file mode 100644
index 0000000000000000000000000000000000000000..8c3bd048a70e5b3237ea8de692c462a65ddb1471
--- /dev/null
+++ b/src/test/java/gov/usgs/earthquake/nshmp/model/GenerateWebActual.java
@@ -0,0 +1,21 @@
+package gov.usgs.earthquake.nshmp.model;
+
+import java.util.Optional;
+
+import gov.usgs.earthquake.nshmp.model.NshmTestUtils.Nshm;
+import gov.usgs.earthquake.nshmp.www.Application;
+import io.micronaut.runtime.Micronaut;
+
+public class GenerateWebActual {
+
+  public static void main(String[] args) {
+    Nshm nshm = NshmTests.NSHMS.get(System.getProperty("NSHM"));
+    var context = Micronaut
+        .build("--model=" + nshm.modelPath())
+        .mainClass(Application.class)
+        .start();
+    NshmTestUtils.writeWebExpecteds(nshm, Optional.of(NshmTests.DATA_PATH));
+    context.close();
+  }
+
+}
diff --git a/src/test/java/gov/usgs/earthquake/nshmp/model/NshmTestUtils.java b/src/test/java/gov/usgs/earthquake/nshmp/model/NshmTestUtils.java
index d786a26297e0637509f22ba5cc29aff033c741f8..e356db568ac0e81dc81880650d27eb38f67d01a0 100644
--- a/src/test/java/gov/usgs/earthquake/nshmp/model/NshmTestUtils.java
+++ b/src/test/java/gov/usgs/earthquake/nshmp/model/NshmTestUtils.java
@@ -139,6 +139,18 @@ class NshmTestUtils {
     }
   }
 
+  static void writeWebExpecteds(
+      Nshm nshm,
+      Optional<Path> dataPath) throws InterruptedException, ExecutionException, IOException {
+    for (NamedLocation location: nshm.locations()) {
+      Map<String, XySequence> xyMap = HazardServiceUtils.generateActual(location, nshm.imts());
+      String json = new StringBuilder(GSON.toJson(xyMap))
+          .append(Text.NEWLINE)
+          .toString();
+      writeExpected(nshm, location, json, dataPath);
+    }
+  }
+
   private static void assertCurveEquals(XySequence expected, XySequence actual, double tol) {
     // IMLs close but not exact due to exp() transform
     assertArrayEquals(