diff --git a/doc/RTD/source/ParameterFiles/parameter_description.rst b/doc/RTD/source/ParameterFiles/parameter_description.rst
index 45b68c9e9c490df52de675ba3d37011d4b48222b..3dfb42fc1ed544c0e45dbdbd0d2aecc76de54ecf 100644
--- a/doc/RTD/source/ParameterFiles/parameter_description.rst
+++ b/doc/RTD/source/ParameterFiles/parameter_description.rst
@@ -686,6 +686,12 @@ creation of a compact range of IDs beyond which the new IDs generated by
 splitting can be safely drawn from. Note that, when ``remap_ids`` is
 switched on the ICs do not need to contain a ``ParticleIDs`` field.
 
+* Name of a HDF5 group to copy from the ICs file(s): ``metadata_group_name`` (default: ``ICs_parameters``)
+
+If the initial conditions generator writes a HDF5 group with the parameters
+used to make the initial conditions, this group can be copied through to
+the output snapshots by specifying its name.
+
 The full section to start a DM+hydro run from Gadget DM-only ICs would
 be:
 
@@ -698,7 +704,7 @@ be:
      cleanup_velocity_factors:    1
      generate_gas_in_ics:         1
      cleanup_smoothing_lengths:   1
-
+     metadata_group_name:         ICs_parameters
 
 .. _Parameters_constants:
 
diff --git a/examples/main.c b/examples/main.c
index 66bd9405ca6f3f543a641049da8caf33309fff50..d93ad058916098672010097315470e39b4356bef 100644
--- a/examples/main.c
+++ b/examples/main.c
@@ -111,6 +111,7 @@ int main(int argc, char *argv[]) {
   struct sink *sinks = NULL;
   struct unit_system us;
   struct los_props los_properties;
+  struct ic_info ics_metadata;
 
   int nr_nodes = 1, myrank = 0;
 
@@ -1140,6 +1141,9 @@ int main(int argc, char *argv[]) {
     size_t Nspart = 0, Nbpart = 0, Nsink = 0;
     double dim[3] = {0., 0., 0.};
 
+    /* Prepare struct to store metadata from ICs */
+    ic_info_init(&ics_metadata, params);
+
     if (myrank == 0) clocks_gettime(&tic);
 #if defined(HAVE_HDF5)
 #if defined(WITH_MPI)
@@ -1150,7 +1154,7 @@ int main(int argc, char *argv[]) {
                      with_gravity, with_sink, with_stars, with_black_holes,
                      with_cosmology, cleanup_h, cleanup_sqrt_a, cosmo.h,
                      cosmo.a, myrank, nr_nodes, MPI_COMM_WORLD, MPI_INFO_NULL,
-                     nr_threads, dry_run, remap_ids);
+                     nr_threads, dry_run, remap_ids, &ics_metadata);
 #else
     read_ic_serial(ICfileName, &us, dim, &parts, &gparts, &sinks, &sparts,
                    &bparts, &Ngas, &Ngpart, &Ngpart_background, &Nnupart,
@@ -1158,7 +1162,7 @@ int main(int argc, char *argv[]) {
                    with_gravity, with_sink, with_stars, with_black_holes,
                    with_cosmology, cleanup_h, cleanup_sqrt_a, cosmo.h, cosmo.a,
                    myrank, nr_nodes, MPI_COMM_WORLD, MPI_INFO_NULL, nr_threads,
-                   dry_run, remap_ids);
+                   dry_run, remap_ids, &ics_metadata);
 #endif
 #else
     read_ic_single(ICfileName, &us, dim, &parts, &gparts, &sinks, &sparts,
@@ -1166,7 +1170,7 @@ int main(int argc, char *argv[]) {
                    &Nsink, &Nspart, &Nbpart, &flag_entropy_ICs, with_hydro,
                    with_gravity, with_sink, with_stars, with_black_holes,
                    with_cosmology, cleanup_h, cleanup_sqrt_a, cosmo.h, cosmo.a,
-                   nr_threads, dry_run, remap_ids);
+                   nr_threads, dry_run, remap_ids, &ics_metadata);
 #endif
 #endif
 
@@ -1424,7 +1428,7 @@ int main(int argc, char *argv[]) {
                 &black_holes_properties, &sink_properties, &neutrino_properties,
                 &feedback_properties, &rt_properties, &mesh, &potential,
                 &cooling_func, &starform, &chemistry, &fof_properties,
-                &los_properties);
+                &los_properties, &ics_metadata);
     engine_config(/*restart=*/0, /*fof=*/0, &e, params, nr_nodes, myrank,
                   nr_threads, nr_pool_threads, with_aff, talking, restart_file);
 
diff --git a/examples/parameter_example.yml b/examples/parameter_example.yml
index c0f3ae565ff970a74b591f3607149a5ff264ff61..be79c2fd669562aa9d89a2fe1c2c171d4e081026 100644
--- a/examples/parameter_example.yml
+++ b/examples/parameter_example.yml
@@ -208,6 +208,7 @@ InitialConditions:
   shift:      [0.0,0.0,0.0]         # (Optional) A shift to apply to all particles read from the ICs (in internal units).
   replicate:  2                     # (Optional) Replicate all particles along each axis a given integer number of times. Default 1.
   remap_ids:  0                     # (Optional) Remap all the particle IDs to the range [1, NumPart].
+  metadata_group_name: ICs_parameters # (Optional) Copy this HDF5 group from the initial conditions file to all snapshots, if found
 
 # Parameters controlling restarts
 Restarts:
diff --git a/src/Makefile.am b/src/Makefile.am
index 6c66de50ffea822d7dbc3a1debf22fdf474fcb66..eb745ec04e90bd95f92670bf563dbda1ee42d08f 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -66,6 +66,7 @@ include_HEADERS += rays.h rays_struct.h
 include_HEADERS += particle_splitting.h particle_splitting_struct.h
 include_HEADERS += chemistry_csds.h star_formation_csds.h
 include_HEADERS += mesh_gravity.h mesh_gravity_mpi.h mesh_gravity_patch.h mesh_gravity_sort.h row_major_id.h
+include_HEADERS += hdf5_object_to_blob.h ic_info.h
 
 # source files for QLA (Ploeckinger+20) cooling
 QLA_COOLING_SOURCES =
@@ -147,6 +148,7 @@ AM_SOURCES += mesh_gravity.c mesh_gravity_mpi.c mesh_gravity_patch.c mesh_gravit
 AM_SOURCES += runner_neutrino.c
 AM_SOURCES += neutrino/Default/fermi_dirac.c neutrino/Default/neutrino.c
 AM_SOURCES += rt_parameters.c
+AM_SOURCES += hdf5_object_to_blob.c ic_info.c
 AM_SOURCES += $(QLA_COOLING_SOURCES) $(QLA_EAGLE_COOLING_SOURCES) 
 AM_SOURCES += $(EAGLE_COOLING_SOURCES) $(EAGLE_FEEDBACK_SOURCES) 
 AM_SOURCES += $(GRACKLE_COOLING_SOURCES) $(GEAR_FEEDBACK_SOURCES) 
diff --git a/src/distributed_io.c b/src/distributed_io.c
index 4569fe47fceadc2b40d41f2b0f48b8c3cc20295e..2510eb156d10a48feac0880680c34f833fcac108 100644
--- a/src/distributed_io.c
+++ b/src/distributed_io.c
@@ -594,6 +594,9 @@ void write_virtual_file(struct engine* e, const char* fileName_base,
   /* Close header */
   H5Gclose(h_grp);
 
+  /* Copy metadata from ICs to the file */
+  ic_info_write_hdf5(e->ics_metadata, h_file);
+
   /* Write all the meta-data */
   io_write_meta_data(h_file, e, internal_units, snapshot_units);
 
@@ -1057,6 +1060,9 @@ void write_output_distributed(struct engine* e,
   /* Close header */
   H5Gclose(h_grp);
 
+  /* Copy metadata from ICs to the file */
+  ic_info_write_hdf5(e->ics_metadata, h_file);
+
   /* Write all the meta-data */
   io_write_meta_data(h_file, e, internal_units, snapshot_units);
 
diff --git a/src/engine.c b/src/engine.c
index a53746b3324a07cfb6523b54b815bdba861cb09c..9f514e8d00383b298e6cdcdf3478538348d7e5f6 100644
--- a/src/engine.c
+++ b/src/engine.c
@@ -2755,6 +2755,7 @@ void engine_unpin(void) {
  * @param chemistry The chemistry information.
  * @param fof_properties The #fof_props of this run.
  * @param los_properties the #los_props of this run.
+ * @param ics_metadata metadata read from the simulation ICs
  */
 void engine_init(
     struct engine *e, struct space *s, struct swift_params *params,
@@ -2773,7 +2774,8 @@ void engine_init(
     struct cooling_function_data *cooling_func,
     const struct star_formation *starform,
     const struct chemistry_global_data *chemistry,
-    struct fof_props *fof_properties, struct los_props *los_properties) {
+    struct fof_props *fof_properties, struct los_props *los_properties,
+    struct ic_info *ics_metadata) {
 
   struct clocks_time tic, toc;
   if (engine_rank == 0) clocks_gettime(&tic);
@@ -2890,6 +2892,7 @@ void engine_init(
   e->output_options = output_options;
   e->stf_this_timestep = 0;
   e->los_properties = los_properties;
+  e->ics_metadata = ics_metadata;
 #ifdef WITH_MPI
   e->usertime_last_step = 0.0;
   e->systime_last_step = 0.0;
@@ -3260,6 +3263,8 @@ void engine_clean(struct engine *e, const int fof, const int restart) {
 
   output_options_clean(e->output_options);
 
+  ic_info_clean(e->ics_metadata);
+
   swift_free("links", e->links);
 #if defined(WITH_CSDS)
   if (e->policy & engine_policy_csds) {
@@ -3322,6 +3327,7 @@ void engine_clean(struct engine *e, const int fof, const int restart) {
     free((void *)e->fof_properties);
 #endif
     free((void *)e->los_properties);
+    free((void *)e->ics_metadata);
 #ifdef WITH_MPI
     free((void *)e->reparttype);
 #endif
@@ -3381,6 +3387,7 @@ void engine_struct_dump(struct engine *e, FILE *stream) {
   fof_struct_dump(e->fof_properties, stream);
 #endif
   los_struct_dump(e->los_properties, stream);
+  ic_info_struct_dump(e->ics_metadata, stream);
   parser_struct_dump(e->parameter_file, stream);
   output_options_struct_dump(e->output_options, stream);
 
@@ -3528,6 +3535,11 @@ void engine_struct_restore(struct engine *e, FILE *stream) {
   los_struct_restore(los_properties, stream);
   e->los_properties = los_properties;
 
+  struct ic_info *ics_metadata =
+    (struct ic_info *)malloc(sizeof(struct ic_info));
+  ic_info_struct_restore(ics_metadata, stream);
+  e->ics_metadata = ics_metadata;
+
   struct swift_params *parameter_file =
       (struct swift_params *)malloc(sizeof(struct swift_params));
   parser_struct_restore(parameter_file, stream);
diff --git a/src/engine.h b/src/engine.h
index 73180940cb0be3af92167301c4e9d4e1c90d8cb4..745a1ad691c35f282c09fdddd20f7b2f72371d26 100644
--- a/src/engine.h
+++ b/src/engine.h
@@ -36,6 +36,7 @@
 #include "barrier.h"
 #include "clocks.h"
 #include "collectgroup.h"
+#include "ic_info.h"
 #include "mesh_gravity.h"
 #include "output_options.h"
 #include "parser.h"
@@ -331,6 +332,9 @@ struct engine {
   double snapshot_delta_from_edge;
   int snapshot_output_count;
 
+  /* Metadata from the ICs */
+  struct ic_info *ics_metadata;
+
   /* Structure finding information */
   double a_first_stf_output;
   double time_first_stf_output;
@@ -613,7 +617,8 @@ void engine_init(
     struct cooling_function_data *cooling_func,
     const struct star_formation *starform,
     const struct chemistry_global_data *chemistry,
-    struct fof_props *fof_properties, struct los_props *los_properties);
+    struct fof_props *fof_properties, struct los_props *los_properties,
+    struct ic_info *ics_metadata);
 void engine_config(int restart, int fof, struct engine *e,
                    struct swift_params *params, int nr_nodes, int nodeID,
                    int nr_task_threads, int nr_pool_threads, int with_aff,
diff --git a/src/hdf5_object_to_blob.c b/src/hdf5_object_to_blob.c
new file mode 100644
index 0000000000000000000000000000000000000000..6243dd125f751a5340ef402a89ebe1ac497aea3c
--- /dev/null
+++ b/src/hdf5_object_to_blob.c
@@ -0,0 +1,167 @@
+/*******************************************************************************
+ * This file is part of SWIFT.
+ * Copyright (c) 2021 John Helly (j.c.helly@durham.ac.uk)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ ******************************************************************************/
+
+/* Config parameters. */
+#include "../config.h"
+
+/* Some standard headers. */
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+
+/* Local headers */
+#include "error.h"
+
+/* This object's header */
+#include "hdf5_object_to_blob.h"
+
+#ifdef HAVE_HDF5
+#include <hdf5.h>
+
+#define MAX_FILENAME_LENGTH 500
+
+/**
+ * @brief Generates a file name using the process ID and host name
+ *
+ * @param prefix Prefix to add to the file name
+ * @param name Buffer to write the file name to
+ * @param len Length of the buffer
+ *
+ */
+static void unique_filename(char *prefix, char *name, size_t len) {
+  
+  /* Get our process ID */
+  long pid = (long) getpid();
+  
+  /* Get our host name. May be truncated or empty. */
+  char hostname[MAX_FILENAME_LENGTH];
+  if(gethostname(hostname, MAX_FILENAME_LENGTH) != 0) {
+    /* gethostname() call failed. Make hostname an empty string. */
+    hostname[0] = (char) 0;
+  } else {
+    /* gethostname() successful. Add null terminator in case of truncation . */
+    hostname[MAX_FILENAME_LENGTH-1] = (char) 0;
+  }
+
+  /* Try to create a unique name. If truncated, try to use it anyway. */
+  int ret = snprintf(name, len, "%s.%s.%ld.tmp", prefix, hostname, pid);
+  if(ret < 0) {
+    error("snprintf call failed generating filename");
+  } else if (((size_t) ret) >= len) {
+    /* Output has been truncated */
+    name[len-1] = (char) 0;    
+  }
+}
+
+
+/**
+ * @brief Copy a HDF5 object and its members to a byte array
+ *
+ * @param group_id Group containing the object to copy
+ * @param name Name of the object
+ * @param len Returns the size of the output array
+ * @param data Returns a pointer to the output array
+ *
+ * This creates a HDF5 file image in memory, copies the required
+ * object to the file image, then returns a copy of the image as
+ * a newly allocated array.
+ *
+ */
+void hdf5_object_to_blob(hid_t group_id, char *name, size_t *len, void **data) {
+ 
+  /* Set up property list */
+  hid_t fapl_id = H5Pcreate(H5P_FILE_ACCESS);
+  const size_t increment = 1024*1024;
+  const hbool_t backing_store = 0;
+  if(H5Pset_fapl_core(fapl_id, increment, backing_store) < 0)
+    error("Unable to set core driver");
+  
+  /* Generate a file name which (hopefully!) doesn't exist */
+  char filename[MAX_FILENAME_LENGTH];
+  unique_filename("/tmp/__SWIFT_HDF5_CORE_WRITE", filename, MAX_FILENAME_LENGTH);
+
+  /* Create the file image in memory (file with this name must not exist) */
+  hid_t file_id = H5Fcreate(filename, H5F_ACC_TRUNC, H5P_DEFAULT, fapl_id);
+  H5Pclose(fapl_id);
+  if(file_id < 0)
+    error("Failed to create HDF5 file in memory");
+
+  /* Copy the input object to the file image */
+  if(H5Ocopy(group_id, name, file_id, name, H5P_DEFAULT, H5P_DEFAULT) < 0)
+    error("Failed to copy HDF5 object %s", name);
+  H5Fflush(file_id, H5F_SCOPE_GLOBAL);
+
+  /* Store the size of the file image */
+  ssize_t size = H5Fget_file_image(file_id, NULL, 0);
+  if(size < 0)
+    error("Failed to get HDF5 file image size");
+  *len = (size_t) size;
+
+  /* Copy the file image to a new data array */
+  *data = malloc(*len);
+  if(H5Fget_file_image(file_id, *data, *len) < 0)
+    error("Failed to copy HDF5 file image to array");
+
+  /* Close the file image */
+  H5Fclose(file_id);
+}
+
+
+/**
+ * @brief Copy a HDF5 object from a byte array to a HDF5 file
+ *
+ * @param len Size of the input byte array
+ * @param data Pointer to the input byte array
+ * @param dest_id HDF5 group in which to write the object
+ * @param name Name of the object
+ *
+ * This opens the HDF5 file image supplied in data and copies
+ * the named object to the HDF5 group specified by dest_id.
+ *
+ */
+void blob_to_hdf5_object(size_t len, void *data, hid_t dest_id, char *name) {
+
+  /* Set up property list */
+  hid_t fapl_id = H5Pcreate(H5P_FILE_ACCESS);
+  const size_t increment = 1024*1024;
+  const hbool_t backing_store = 0;
+  if(H5Pset_fapl_core(fapl_id, increment, backing_store) < 0)
+    error("Unable to set core driver");
+  if(H5Pset_file_image(fapl_id, data, len) < 0)
+    error("Unable to set file image");
+
+  /* Generate a file name which (hopefully!) doesn't exist */
+  char filename[MAX_FILENAME_LENGTH];
+  unique_filename("/tmp/__SWIFT_HDF5_CORE_READ", filename, MAX_FILENAME_LENGTH);
+
+  /* Open the file image (file with this name must not exist) */
+  hid_t file_id = H5Fopen(filename, H5F_ACC_RDONLY, fapl_id); 
+  if(file_id < 0)
+    error("Opening HDF5 file image failed, possibly because file %s already exists", filename);
+  H5Pclose(fapl_id);
+
+  /* Copy the object from the file image to the destination */
+  if(H5Ocopy(file_id, name, dest_id, name, H5P_DEFAULT, H5P_DEFAULT) < 0)
+    error("Failed to copy HDF5 object %s", name);
+
+  /* Close the file image */
+  H5Fclose(file_id);
+}
+
+#endif
diff --git a/src/hdf5_object_to_blob.h b/src/hdf5_object_to_blob.h
new file mode 100644
index 0000000000000000000000000000000000000000..733a623eb2d806b37e6d38332b0c126489441bc8
--- /dev/null
+++ b/src/hdf5_object_to_blob.h
@@ -0,0 +1,35 @@
+/*******************************************************************************
+ * This file is part of SWIFT.
+ * Copyright (c) 2021 John Helly (j.c.helly@durham.ac.uk)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ ******************************************************************************/
+
+#ifndef SWIFT_HDF5_OBJECT_TO_BLOB_H
+#define SWIFT_HDF5_OBJECT_TO_BLOB_H
+
+/* Config parameters. */
+#include "../config.h"
+
+#ifdef HAVE_HDF5
+
+#include <hdf5.h>
+
+void hdf5_object_to_blob(hid_t group_id, char *name, size_t *len, void **data);
+void blob_to_hdf5_object(size_t len, void *data, hid_t dest_id, char *name);
+
+#endif /* HAVE_HDF5 */
+
+#endif /* SWIFT_HDF5_OBJECT_TO_BLOB_H */
diff --git a/src/ic_info.c b/src/ic_info.c
new file mode 100644
index 0000000000000000000000000000000000000000..432a8effa0fa386e03f44c4035ed3e577f9131ab
--- /dev/null
+++ b/src/ic_info.c
@@ -0,0 +1,188 @@
+/*******************************************************************************
+ * This file is part of SWIFT.
+ * Copyright (c) 2021 John Helly (j.c.helly@durham.ac.uk)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ ******************************************************************************/
+
+/* Config parameters. */
+#include "../config.h"
+
+/* Some standard headers. */
+#include <stdlib.h>
+#include <stdio.h>
+#ifdef WITH_MPI
+#include <mpi.h>
+#endif
+
+/* Local headers */
+#include "error.h"
+
+/* This object's header */
+#include "ic_info.h"
+
+/* Includes */
+#include "hdf5_object_to_blob.h"
+#include "restart.h"
+
+extern int engine_rank;
+
+/**
+ * @brief Initialize the ic_info struct
+ *
+ * @param ics Pointer to the struct
+ * @param params The Swift parameter set
+ */
+void ic_info_init(struct ic_info *ics, struct swift_params *params) {
+  
+  /* Initially we have no file image */
+  ics->file_image_length = 0;
+  ics->file_image_data = NULL;
+
+  /* Store the name of the HDF5 group to copy */
+  parser_get_opt_param_string(params,
+                              "InitialConditions:metadata_group_name",
+                              ics->group_name, "ICs_parameters");
+}
+
+/**
+ * @brief Clean up the ic_info struct
+ *
+ * @param ics Pointer to the struct
+ */
+void ic_info_clean(struct ic_info *ics) {
+
+  /* Deallocate file image, if it exists */
+  if(ics->file_image_data) {
+    free(ics->file_image_data);
+    ics->file_image_data = NULL;
+  }
+  ics->file_image_length = 0;
+
+}
+
+/**
+ * @brief Dump the ic_info struct to the supplied file
+ *
+ * @param ics Pointer to the struct
+ * @param stream The file to write to
+ */
+void ic_info_struct_dump(struct ic_info *ics, FILE *stream) {
+  
+  /* Write the struct */
+  restart_write_blocks(ics, sizeof(struct ic_info), 1, stream,
+                       "ic_info", "ic_info struct");
+
+  /* Write the HDF5 file image if there is one */
+  if(ics->file_image_data) {
+    restart_write_blocks(ics->file_image_data, ics->file_image_length,
+                         1, stream, "ic_info", "ic_info file image");
+  }
+}
+
+/**
+ * @brief Restore the ic_info struct from the supplied file
+ *
+ * @param ics Pointer to the struct
+ * @param stream The file to read from
+ */
+void ic_info_struct_restore(struct ic_info *ics, FILE *stream) {
+
+  /* Read in the struct */
+  restart_read_blocks(ics, sizeof(struct ic_info), 1, stream,
+                      NULL, "ic_info struct");
+
+  /* Read in the HDF5 file image, if there is one */
+  if(ics->file_image_data) {
+    ics->file_image_data = malloc(ics->file_image_length);
+    restart_read_blocks(ics->file_image_data, ics->file_image_length,
+                        1, stream, NULL, "ic_info file image");
+  }
+}
+
+/**
+ * @brief Broadcast the ic_info struct to all MPI ranks
+ *
+ * @param ics Pointer to the struct
+ * @param root The root rank for the broadcast operation
+ */
+void ic_info_struct_broadcast(struct ic_info *ics, int root) {
+
+#ifdef WITH_MPI
+  
+  int rank;
+  MPI_Comm_rank(MPI_COMM_WORLD, &rank);
+
+  /* Broadcast the struct */
+  MPI_Bcast(ics, sizeof(struct ic_info), MPI_BYTE, root, MPI_COMM_WORLD);
+  if(ics->file_image_data) {
+
+    /* Allocate file image data on other ranks */
+    if(rank != root)
+      ics->file_image_data = malloc(ics->file_image_length);
+    
+    /* Broadcast the file image data */
+    MPI_Bcast(ics->file_image_data, ics->file_image_length,
+              MPI_BYTE, root, MPI_COMM_WORLD);
+  }
+#endif
+}
+
+
+#ifdef HAVE_HDF5
+/**
+ * @brief Read the ICs metadata from a HDF5 file
+ *
+ * @param ics Pointer to the struct
+ * @param file_id The HDF5 file (or group) to write to
+ */
+void ic_info_read_hdf5(struct ic_info *ics, hid_t file_id) {
+  
+  /* Check that the named group exists as a link in the ICs file */
+  if(H5Lexists(file_id, ics->group_name, H5P_DEFAULT) > 0) {
+    /* Check that the link resolves to an object */
+    if(H5Oexists_by_name(file_id, ics->group_name, H5P_DEFAULT) > 0) {      
+      /* Read the HDF5 object into memory */
+      hdf5_object_to_blob(file_id, ics->group_name, &(ics->file_image_length),
+                          &(ics->file_image_data));
+      if(engine_rank==0)
+        message("Read metadata group %s from ICs file", ics->group_name);
+    } else {
+      if(engine_rank==0)
+        message("Metadata group %s in ICs file appears to be a broken link",
+                ics->group_name);
+    }
+  } else {
+    if(engine_rank==0)
+      message("Metadata group %s not found in ICs file", ics->group_name);
+  }
+}
+
+
+/**
+ * @brief Write the ICs metadata to a HDF5 file
+ *
+ * @param ics Pointer to the struct
+ * @param file_id The HDF5 file (or group) to read from
+ */
+void ic_info_write_hdf5(struct ic_info *ics, hid_t file_id) {
+  
+  if(ics->file_image_data) {
+      blob_to_hdf5_object(ics->file_image_length, ics->file_image_data, file_id,
+                          ics->group_name);
+    }
+}
+#endif
+
diff --git a/src/ic_info.h b/src/ic_info.h
new file mode 100644
index 0000000000000000000000000000000000000000..8885d7cda29f211cd4888fad8c822b119e4e26bf
--- /dev/null
+++ b/src/ic_info.h
@@ -0,0 +1,50 @@
+/*******************************************************************************
+ * This file is part of SWIFT.
+ * Copyright (c) 2021 John Helly (j.c.helly@durham.ac.uk)
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Lesser General Public License as published
+ * by the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public License
+ * along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ ******************************************************************************/
+
+#ifndef SWIFT_IC_INFO_H
+#define SWIFT_IC_INFO_H
+
+/* Config parameters. */
+#include "../config.h"
+
+/* Some standard headers. */
+#include <stdlib.h>
+#include <stdio.h>
+
+/* Includes. */
+#include "parser.h"
+
+struct ic_info {
+  char group_name[PARSER_MAX_LINE_SIZE];
+  size_t file_image_length;
+  void *file_image_data;
+};
+
+void ic_info_init(struct ic_info *ics, struct swift_params *params);
+void ic_info_clean(struct ic_info *ics);
+void ic_info_struct_dump(struct ic_info *ics, FILE *stream);
+void ic_info_struct_restore(struct ic_info *ics, FILE *stream);
+void ic_info_struct_broadcast(struct ic_info *ics, int root);
+
+#ifdef HAVE_HDF5
+void ic_info_read_hdf5(struct ic_info *ics, hid_t file_id);
+void ic_info_write_hdf5(struct ic_info *ics, hid_t file_id);
+#endif
+
+#endif /* SWIFT_IC_INFO_H */
diff --git a/src/parallel_io.c b/src/parallel_io.c
index cf566a8c06bfea0b2af6cde3ea2f571675d1ff27..2d4b0d242a3363be06df0be1ca9d5e7995e2fad2 100644
--- a/src/parallel_io.c
+++ b/src/parallel_io.c
@@ -47,6 +47,7 @@
 #include "gravity_properties.h"
 #include "hydro_io.h"
 #include "hydro_properties.h"
+#include "ic_info.h"
 #include "io_properties.h"
 #include "memuse.h"
 #include "output_list.h"
@@ -750,6 +751,8 @@ void write_array_parallel(struct engine* e, hid_t grp, char* fileName,
  * @param info The MPI information object
  * @param n_threads The number of threads to use for local operations.
  * @param dry_run If 1, don't read the particle. Only allocates the arrays.
+ * @param remap_ids Are we ignoring the ICs' IDs and remapping them to [1, N[ ?
+ * @param ics_metadata Will store metadata group copied from the ICs file
  *
  */
 void read_ic_parallel(char* fileName, const struct unit_system* internal_units,
@@ -763,7 +766,7 @@ void read_ic_parallel(char* fileName, const struct unit_system* internal_units,
                       int with_cosmology, int cleanup_h, int cleanup_sqrt_a,
                       double h, double a, int mpi_rank, int mpi_size,
                       MPI_Comm comm, MPI_Info info, int n_threads, int dry_run,
-                      int remap_ids) {
+                      int remap_ids, struct ic_info *ics_metadata) {
 
   hid_t h_file = 0, h_grp = 0;
   /* GADGET has only cubic boxes (in cosmological mode) */
@@ -905,6 +908,9 @@ void read_ic_parallel(char* fileName, const struct unit_system* internal_units,
     }
   }
 
+  /* Read metadata from ICs file */
+  ic_info_read_hdf5(ics_metadata, h_file);
+
   /* Convert the dimensions of the box */
   for (int j = 0; j < 3; j++)
     dim[j] *=
@@ -1271,6 +1277,9 @@ void prepare_file(struct engine* e, const char* fileName,
   /* Close header */
   H5Gclose(h_grp);
 
+  /* Copy metadata from ICs to the file */
+  ic_info_write_hdf5(e->ics_metadata, h_file);
+
   /* Write all the meta-data */
   io_write_meta_data(h_file, e, internal_units, snapshot_units);
 
diff --git a/src/parallel_io.h b/src/parallel_io.h
index 647301e7639f6008539724a157a09d201575b894..dd1d4697d054cd39f4dc5a4cdb718474bec1aca2 100644
--- a/src/parallel_io.h
+++ b/src/parallel_io.h
@@ -29,6 +29,7 @@
 
 /* Includes. */
 #include "part.h"
+#include "ic_info.h"
 
 struct engine;
 struct unit_system;
@@ -44,7 +45,7 @@ void read_ic_parallel(char* fileName, const struct unit_system* internal_units,
                       int with_cosmology, int cleanup_h, int cleanup_sqrt_a,
                       double h, double a, int mpi_rank, int mpi_size,
                       MPI_Comm comm, MPI_Info info, int nr_threads, int dry_run,
-                      int remap_ids);
+                      int remap_ids, struct ic_info *ics_metadata);
 
 void write_output_parallel(struct engine* e,
                            const struct unit_system* internal_units,
diff --git a/src/serial_io.c b/src/serial_io.c
index a5863b6782e452c3dabcf61de31707ea405caf68..0d3e0414d1afab0632ecb70563badac7932426f4 100644
--- a/src/serial_io.c
+++ b/src/serial_io.c
@@ -515,6 +515,7 @@ void write_array_serial(const struct engine* e, hid_t grp, char* fileName,
  * @param n_threads The number of threads to use for local operations.
  * @param dry_run If 1, don't read the particle. Only allocates the arrays.
  * @param remap_ids Are we ignoring the ICs' IDs and remapping them to [1, N[ ?
+ * @param ics_metadata Will store metadata group copied from the ICs file
  *
  * Opens the HDF5 file fileName and reads the particles contained
  * in the parts array. N is the returned number of particles found
@@ -535,7 +536,7 @@ void read_ic_serial(char* fileName, const struct unit_system* internal_units,
                     int with_cosmology, int cleanup_h, int cleanup_sqrt_a,
                     double h, double a, int mpi_rank, int mpi_size,
                     MPI_Comm comm, MPI_Info info, int n_threads, int dry_run,
-                    int remap_ids) {
+                    int remap_ids, struct ic_info *ics_metadata) {
 
   hid_t h_file = 0, h_grp = 0;
   /* GADGET has only cubic boxes (in cosmological mode) */
@@ -672,6 +673,9 @@ void read_ic_serial(char* fileName, const struct unit_system* internal_units,
               internal_units->UnitTemperature_in_cgs);
     }
 
+    /* Read metadata from ICs file */
+    ic_info_read_hdf5(ics_metadata, h_file);
+
     /* Close file */
     H5Fclose(h_file);
   }
@@ -686,6 +690,7 @@ void read_ic_serial(char* fileName, const struct unit_system* internal_units,
   MPI_Bcast(N_total, swift_type_count, MPI_LONG_LONG_INT, 0, comm);
   MPI_Bcast(dim, 3, MPI_DOUBLE, 0, comm);
   MPI_Bcast(ic_units, sizeof(struct unit_system), MPI_BYTE, 0, comm);
+  ic_info_struct_broadcast(ics_metadata, 0);
 
   /* Divide the particles among the tasks. */
   for (int ptype = 0; ptype < swift_type_count; ++ptype) {
@@ -1226,6 +1231,9 @@ void write_output_serial(struct engine* e,
     /* Close header */
     H5Gclose(h_grp);
 
+    /* Copy metadata from ICs to the file */
+    ic_info_write_hdf5(e->ics_metadata, h_file);
+
     /* Write all the meta-data */
     io_write_meta_data(h_file, e, internal_units, snapshot_units);
 
diff --git a/src/serial_io.h b/src/serial_io.h
index f89d901799433c1173f92f9cb7faf8e3838fc145..b7d906d0dcbecef5b14a94d54b6c9a87a030e348 100644
--- a/src/serial_io.h
+++ b/src/serial_io.h
@@ -31,6 +31,7 @@
 
 /* Includes. */
 #include "part.h"
+#include "ic_info.h"
 
 struct engine;
 struct unit_system;
@@ -46,7 +47,7 @@ void read_ic_serial(char* fileName, const struct unit_system* internal_units,
                     int with_cosmology, int cleanup_h, int cleanup_sqrt_a,
                     double h, double a, int mpi_rank, int mpi_size,
                     MPI_Comm comm, MPI_Info info, int n_threads, int dry_run,
-                    int remap_ids);
+                    int remap_ids, struct ic_info *ics_metadata);
 
 void write_output_serial(struct engine* e,
                          const struct unit_system* internal_units,
diff --git a/src/single_io.c b/src/single_io.c
index 133f0010716c593b815f97b82f32836def62d74d..32a9f9a3db72aa5b96aae4bd536c79d26f585ea0 100644
--- a/src/single_io.c
+++ b/src/single_io.c
@@ -418,6 +418,8 @@ void write_array_single(const struct engine* e, hid_t grp, char* fileName,
  * @param a The current value of the scale-factor.
  * @prarm n_threads The number of threads to use for the temporary threadpool.
  * @param dry_run If 1, don't read the particle. Only allocates the arrays.
+ * @param remap_ids Are we ignoring the ICs' IDs and remapping them to [1, N[ ?
+ * @param ics_metadata Will store metadata group copied from the ICs file
  *
  * Opens the HDF5 file fileName and reads the particles contained
  * in the parts array. N is the returned number of particles found
@@ -434,7 +436,8 @@ void read_ic_single(
     size_t* Nsinks, size_t* Nstars, size_t* Nblackholes, int* flag_entropy,
     int with_hydro, int with_gravity, int with_sink, int with_stars,
     int with_black_holes, int with_cosmology, int cleanup_h, int cleanup_sqrt_a,
-    double h, double a, int n_threads, int dry_run, int remap_ids) {
+    double h, double a, int n_threads, int dry_run, int remap_ids,
+    struct ic_info *ics_metadata) {
 
   hid_t h_file = 0, h_grp = 0;
   /* GADGET has only cubic boxes (in cosmological mode) */
@@ -563,6 +566,9 @@ void read_ic_single(
             internal_units->UnitTemperature_in_cgs);
   }
 
+  /* Read metadata from ICs file */
+  ic_info_read_hdf5(ics_metadata, h_file);
+
   /* Convert the dimensions of the box */
   for (int j = 0; j < 3; j++)
     dim[j] *=
@@ -1057,6 +1063,9 @@ void write_output_single(struct engine* e,
   /* Close header */
   H5Gclose(h_grp);
 
+  /* Copy metadata from ICs to the file */
+  ic_info_write_hdf5(e->ics_metadata, h_file);
+
   /* Write all the meta-data */
   io_write_meta_data(h_file, e, internal_units, snapshot_units);
 
diff --git a/src/single_io.h b/src/single_io.h
index a2b423562589d2a577a6a4817b18b68cc1fb86a9..da769be602323f0ba29c50d250c6a161d4e95cdb 100644
--- a/src/single_io.h
+++ b/src/single_io.h
@@ -26,6 +26,7 @@
 
 /* Local includes */
 #include "part.h"
+#include "ic_info.h"
 
 struct engine;
 struct unit_system;
@@ -40,7 +41,8 @@ void read_ic_single(const char* fileName,
                     int with_hydro, int with_gravity, int with_sinks,
                     int with_stars, int with_black_holes, int with_cosmology,
                     int cleanup_h, int cleanup_sqrt_a, double h, double a,
-                    int nr_threads, int dry_run, int remap_ids);
+                    int nr_threads, int dry_run, int remap_ids,
+                    struct ic_info *ics_metadata);
 
 void write_output_single(struct engine* e,
                          const struct unit_system* internal_units,
diff --git a/src/swift.h b/src/swift.h
index 2365cc175dabcd5adbf0b492401975766426919c..b112766b5fbc09bd2ef6f0fdf47242e8eecd84f7 100644
--- a/src/swift.h
+++ b/src/swift.h
@@ -51,6 +51,7 @@
 #include "hashmap.h"
 #include "hydro.h"
 #include "hydro_properties.h"
+#include "ic_info.h"
 #include "line_of_sight.h"
 #include "lock.h"
 #include "map.h"